diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..2cb24879 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,3 @@ +[report] +omit = pelican/tests/* + diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..dfe07704 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore index 9f9404ef..1ae0e9f6 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ tags .tox .coverage htmlcov +six-*.egg/ +*.orig diff --git a/.hgignore b/.hgignore deleted file mode 100644 index a0f6b7c5..00000000 --- a/.hgignore +++ /dev/null @@ -1,9 +0,0 @@ -syntax: glob -output/* -*.pyc -MANIFEST -build -dist -docs/_build -Paste-* -*.egg-info diff --git a/.hgtags b/.hgtags deleted file mode 100644 index 6d4c8d99..00000000 --- a/.hgtags +++ /dev/null @@ -1,29 +0,0 @@ -7acafbf7e47b1287525026ad8b4f1efe443d5403 1.2 -7acafbf7e47b1287525026ad8b4f1efe443d5403 1.2 -ae850ab0fd62a98a98da7ce74ac794319c6a5066 1.2 -54a0309f79d6c5b54d8e1e3b5e3f744856b68a73 1.1 -8f5e0eb037768351eb08840e588a4364266a69b3 1.1.1 -bb986ed591734ca469f726753cbc48ebbfce0dcc 1.2.1 -8a3dad99cbfa6bb5d0ef073213d0d86e0b4c5dba 1.2.2 -4a20105a242ab154f6202aa6651979bfbb4cf95e 1.2.3 -803aa0976cca3dd737777c640722988b1f3769fe 1.2.4 -703c4511105fd9c8b85afda951a294c194e7cf3e 1.2.5 -6e46a40aaa850a979f5d09dd95d02791ec7ab0ef 2.0 -bf14d1a5c1fae9475447698f0f9b8d35c551f732 2.1 -da86343ebd543e5865050e47ecb0937755528d13 2.1.1 -760187f048bb23979402f950ecb5d3c5493995b1 2.2 -20aa16fe4daa3b70f6c063f170edc916b49837ed 2.3 -f9c1d94081504f21f5b2ba147a38099e45db1769 2.4 -e65199a0b2706d2fb48f7a3c015e869716e0bec1 2.4.1 -89dbd7b6f114508eae62fc821326f4797dfc8b23 2.4.2 -979b4473af56a191a278c83058bc9c8fa1fde30e 2.4.3 -26a444fbb78becae358afa0a5b47587db8739b21 2.4.4 -3542b65fd1963ae7065b6a3bc912fbb6c150e98c 2.4.5 -87745dfdd51b96bf18eaaf6c402effa902c1b856 2.5.0 -294a2830a393d5a97671dc211dbdb5254a15e604 2.5.1 -294a2830a393d5a97671dc211dbdb5254a15e604 2.5.1 -92b31e41134cb2c1a156ce623338cf634d2ebc3e 2.5.1 -7d728f8e771cbbc802ce81e424e08a8eecbd48dc 2.5.2 -7d728f8e771cbbc802ce81e424e08a8eecbd48dc 2.5.2 -6d368a1739a4ce48d2d04b00db04fa538e2bf90a 2.5.2 -1f9dd44b546425216b1fa35fd88d3d532da8916b 2.5.3 diff --git a/.mailmap b/.mailmap new file mode 100644 index 00000000..8dd40fb6 --- /dev/null +++ b/.mailmap @@ -0,0 +1,24 @@ +Alexis Métaireau +Alexis Métaireau +Alexis Métaireau +Axel Haustant +Axel Haustant +Dave Mankoff +Feth Arezki +Guillaume +Guillaume +Guillaume B +Guillermo López +Guillermo López +Jomel Imperio +Justin Mayer +Justin Mayer +Marco Milanesi +Massimo Santini +Rémy HUBSCHER +Simon Conseil +Simon Liedtke +Skami18 +Stuart Colville +Stéphane Bunel +tBunnyMan diff --git a/.travis.yml b/.travis.yml index ea134da4..54dcf0ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,22 @@ language: python python: - - "2.6" - "2.7" + - "3.3" + - "3.4" +before_install: + - sudo apt-get update -qq + - sudo locale-gen fr_FR.UTF-8 tr_TR.UTF-8 install: - - pip install nose unittest2 mock --use-mirrors - - pip install . --use-mirrors - - pip install Markdown -script: nosetests -s tests + - pip install . + - pip install -r dev_requirements.txt + - pip install nose-cov +script: nosetests -sv --with-coverage --cover-package=pelican pelican +after_success: + # Report coverage results to coveralls.io + - pip install coveralls + - coveralls notifications: irc: - channels: + channels: - "irc.freenode.org#pelican" on_success: change diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 00000000..85d30c97 --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,144 @@ +Filing issues +------------- + +* Before you file an issue, try `asking for help`_ first. +* If determined to file an issue, first check for `existing issues`_, including + closed issues. + +.. _`asking for help`: `How to get help`_ +.. _`existing issues`: https://github.com/getpelican/pelican/issues + +How to get help +--------------- + +Before you ask for help, please make sure you do the following: + +1. Read the documentation_ thoroughly. If in a hurry, at least use the search + field that is provided at top-right on the documentation_ pages. Make sure + you read the docs for the Pelican version you are using. +2. Use a search engine (e.g., DuckDuckGo, Google) to search for a solution to + your problem. Someone may have already found a solution, perhaps in the + form of a plugin_ or a specific combination of settings. + +3. Try reproducing the issue in a clean environment, ensuring you are using: + +* latest Pelican release (or an up-to-date git clone of Pelican master) +* latest releases of libraries used by Pelican +* no plugins or only those related to the issue + +**NOTE:** The most common sources of problems are anomalies in (1) themes, +(2) settings files, and (3) ``make``/``fab`` automation wrappers. If you can't +reproduce your problem when using the following steps to generate your site, +then the problem is almost certainly with your chosen theme and/or settings +file (and not Pelican itself):: + + cd ~/projects/your-site + git clone https://github.com/getpelican/pelican ~/projects/pelican + pelican content -s ~/projects/pelican/samples/pelican.conf.py -t ~/projects/pelican/pelican/themes/notmyidea + +If despite the above efforts you still cannot resolve your problem, be sure to +include in your inquiry the following information, preferably in the form of +links to content uploaded to a `paste service`_, GitHub repository, or other +publicly-accessible location: + +* Describe what version of Pelican you are running (output of ``pelican --version`` + or the HEAD commit hash if you cloned the repo) and how exactly you installed + it (the full command you used, e.g. ``pip install pelican``). +* If you are looking for a way to get some end result, prepare a detailed + description of what the end result should look like (preferably in the form of + an image or a mock-up page) and explain in detail what you have done so far to + achieve it. +* If you are trying to solve some issue, prepare a detailed description of how + to reproduce the problem. If the issue cannot be easily reproduced, it cannot + be debugged by developers or volunteers. Describe only the **minimum steps** + necessary to reproduce it (no extra plugins, etc.). +* Upload your settings file or any other custom code that would enable people to + reproduce the problem or to see what you have already tried to achieve the + desired end result. +* Upload detailed and **complete** output logs and backtraces (remember to add + the ``--debug`` flag: ``pelican --debug content [...]``) + +.. _documentation: http://docs.getpelican.com/ +.. _`paste service`: https://dpaste.de/ + +Once the above preparation is ready, you can contact people willing to help via +(preferably) the ``#pelican`` IRC channel or send a message to ``authors at getpelican dot com``. +Remember to include all the information you prepared. + +The #pelican IRC channel +........................ + +* Because of differing time zones, you may not get an immediate response to your + question, but please be patient and stay logged into IRC — someone will almost + always respond if you wait long enough (it may take a few hours). +* If you don't have an IRC client handy, use the webchat_ for quick feedback. +* You can direct your IRC client to the channel using this `IRC link`_ or you + can manually join the ``#pelican`` IRC channel on the `freenode IRC network`_. + +.. _webchat: https://kiwiirc.com/client/irc.freenode.net/?#pelican +.. _`IRC link`: irc://irc.freenode.org/pelican +.. _`freenode IRC network`: http://www.freenode.org/ + + +Contributing code +----------------- + +Before you submit a contribution, please ask whether it is desired so that you +don't spend a lot of time working on something that would be rejected for a +known reason. Consider also whether your new feature might be better suited as +a plugin_ — you can `ask for help`_ to make that determination. + +Using Git and GitHub +.................... + +* `Create a new git branch`_ specific to your change (as opposed to making + your commits in the master branch). +* **Don't put multiple unrelated fixes/features in the same branch / pull request.** + For example, if you're hacking on a new feature and find a bugfix that + doesn't *require* your new feature, **make a new distinct branch and pull + request** for the bugfix. +* Check for unnecessary whitespace via ``git diff --check`` before committing. +* First line of your commit message should start with present-tense verb, be 50 + characters or less, and include the relevant issue number(s) if applicable. + *Example:* ``Ensure proper PLUGIN_PATH behavior. Refs #428.`` If the commit + *completely fixes* an existing bug report, please use ``Fixes #585`` or ``Fix + #585`` syntax (so the relevant issue is automatically closed upon PR merge). +* After the first line of the commit message, add a blank line and then a more + detailed explanation (when relevant). +* `Squash your commits`_ to eliminate merge commits and ensure a clean and + readable commit history. +* If you have previously filed a GitHub issue and want to contribute code that + addresses that issue, **please use** ``hub pull-request`` instead of using + GitHub's web UI to submit the pull request. This isn't an absolute + requirement, but makes the maintainers' lives much easier! Specifically: + `install hub `_ and then run + `hub pull-request `_ to + turn your GitHub issue into a pull request containing your code. + +Contribution quality standards +.............................. + +* Adhere to `PEP8 coding standards`_ whenever possible. This can be eased via + the `pep8 `_ or `flake8 + `_ tools, the latter of which in + particular will give you some useful hints about ways in which the + code/formatting can be improved. +* Make sure your code is compatible with Python 2.7, 3.3, and 3.4 — see our + `compatibility cheatsheet`_ for more details. +* Add docs and tests for your changes. Undocumented and untested features will + not be accepted. +* `Run all the tests`_ **on all versions of Python supported by Pelican** to + ensure nothing was accidentally broken. + +Check out our `Git Tips`_ page or `ask for help`_ if you +need assistance or have any questions about these guidelines. + +.. _`plugin`: http://docs.getpelican.com/en/latest/plugins.html +.. _`#pelican IRC channel`: http://webchat.freenode.net/?channels=pelican&uio=d4 +.. _`Create a new git branch`: https://github.com/getpelican/pelican/wiki/Git-Tips#making-your-changes +.. _`Squash your commits`: https://github.com/getpelican/pelican/wiki/Git-Tips#squashing-commits +.. _`Run all the tests`: http://docs.getpelican.com/en/latest/contribute.html#running-the-test-suite +.. _`Git Tips`: https://github.com/getpelican/pelican/wiki/Git-Tips +.. _`PEP8 coding standards`: http://www.python.org/dev/peps/pep-0008/ +.. _`ask for help`: `How to get help`_ +.. _`compatibility cheatsheet`: http://docs.getpelican.com/en/latest/contribute.html#python-3-development-tips diff --git a/MANIFEST.in b/MANIFEST.in index bec6d1a3..dcf9ea45 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,3 @@ include *.rst -global-include *.py -recursive-include pelican *.html *.css *png *.in -include LICENSE THANKS -recursive-include tests * -recursive-exclude tests *.pyc +recursive-include pelican *.html *.css *png *.in *.rst *.md *.mkd *.xml *.py +include LICENSE THANKS docs/changelog.rst diff --git a/README.rst b/README.rst index 27693037..8642ebaa 100644 --- a/README.rst +++ b/README.rst @@ -1,9 +1,5 @@ -Pelican -======= - -.. image:: https://secure.travis-ci.org/getpelican/pelican.png?branch=master - :target: http://travis-ci.org/#!/getpelican/pelican - :alt: Travis-ci: continuous integration status. +Pelican |build-status| |coverage-status| +======================================== Pelican is a static site generator, written in Python_. @@ -27,9 +23,9 @@ Pelican currently supports: * Publication of articles in multiple languages * Atom/RSS feeds * Code syntax highlighting -* Compilation of `LESS CSS`_ (optional) * Import from WordPress, Dotclear, or RSS feeds * Integration with external tools: Twitter, Google Analytics, etc. (optional) +* Fast rebuild times thanks to content caching and selective output writing. Have a look at the `Pelican documentation`_ for more information. @@ -45,16 +41,23 @@ You can access the source code at: https://github.com/getpelican/pelican If you feel hackish, have a look at the explanation of `Pelican's internals`_. -Feedback / Contact us ---------------------- +How to get help, contribute, or provide feedback +------------------------------------------------ -If you want to see new features in Pelican, don't hesitate to offer -suggestions, clone the repository, etc. There are many ways to contribute_. -That's open source, dude! +See our `contribution submission and feedback guidelines `_. -Contact me at "alexis at notmyidea dot org" for any request/feedback! You can -also join the team at `#pelican on irc.freenode.org -`_ -(or if you don't have any IRC client, use `the webchat -`_) -for quick feedback. +.. Links + +.. _Python: http://www.python.org/ +.. _reStructuredText: http://docutils.sourceforge.net/rst.html +.. _Markdown: http://daringfireball.net/projects/markdown/ +.. _Jinja2: http://jinja.pocoo.org/ +.. _`Pelican documentation`: http://docs.getpelican.com/ +.. _`Pelican's internals`: http://docs.getpelican.com/en/latest/internals.html + +.. |build-status| image:: https://travis-ci.org/getpelican/pelican.svg?branch=master + :target: https://travis-ci.org/getpelican/pelican + :alt: Travis CI: continuous integration status +.. |coverage-status| image:: https://img.shields.io/coveralls/getpelican/pelican.svg + :target: https://coveralls.io/r/getpelican/pelican + :alt: Coveralls: code coverage status diff --git a/THANKS b/THANKS index 2a20100e..15503473 100644 --- a/THANKS +++ b/THANKS @@ -1,19 +1,158 @@ -Some people have helped to improve pelican by contributing features, reporting -bugs or giving ideas. Thanks to them ! +Pelican is a project originally created by Alexis Métaireau +, but there are a large number of people that have +contributed or implemented key features over time. We do our best to keep this +list up-to-date, but you can also have a look at the nice contributor graphs +produced by GitHub: https://github.com/getpelican/pelican/graphs/contributors -- Dan Jacka -- solsTiCe on linuxfr for reporting bugs -- Guillaume B (Gui13) -- Ronny Pfannschmidt -- Jérome Renard -- Nicolas Martin -- David Kulak -- Arnaud Bos -- nblock (Florian) -- Bruno Bord -- Laureline Guérin -- Samuel Martin -- Marcus Fredriksson -- Günter Kolousek -- Simon Liedtke -- Manuel F. Viera +If you want to contribute, check the documentation section about how to do so: + + +Aaron Kavlie +Abhishek L +Albrecht Mühlenschulte +Aldiantoro Nugroho +Alen Mujezinovic +Alessandro Martin +Alexander Artemenko +Alexandre RODIERE +Alexis Daboville +Alexis Métaireau +Allan Whatmough +Andrea Crotti +Andrew Laski +Andrew Spiers +Arnaud BOS +asselinpaul +Axel Haustant +Benoît HERVIER +Borgar +Brandon W Maister +Brendan Wholihan +Brian C. Lane +Brian Hsu +Brian St. Pierre +Bruno Binet +BunnyMan +Chenguang Wang +Chris Elston +Chris McDonald (Wraithan) +Chris Streeter +Christophe Chauvet +Clint Howarth +Colin Dunklau +Dafydd Crosby +Dana Woodman +Dave King +Dave Mankoff +David Beitey +David Marble +Deniz Turgut (Avaris) +derdon +Dirkjan Ochtman +Dirk Makowski +draftcode +Edward Delaporte +Emily Strickland +epatters +Eric Case +Erik Hetzner +FELD Boris +Feth Arezki +Florian Jacob +Florian Preinstorfer +Félix Delval +Freeculture +George V. Reilly +Guillaume +Guillaume B +Guillermo López +guillermooo +Ian Cordasco +Igor Kalnitsky +Irfan Ahmad +Iuri de Silvio +Ivan Dyedov +James King +James Rowe +jawher +Jered Boxman +Jerome +Jiachen Yang +Jochen Breuer +joe di castro +John Kristensen +John Mastro +Jökull Sólberg Auðunsson +Jomel Imperio +Joseph Reagle +Joshua Adelman +Julian Berman +Justin Mayer +Kevin Deldycke +Kyle Fuller +Laureline Guerin +Leonard Huang +Leroy Jiang +Marcel Hellkamp +Marco Milanesi +Marcus Fredriksson +Mario Rodas +Mark Caudill +Martin Brochhaus +Massimo Santini +Matt Bowcock +Matt Layman +Meir Kriheli +Michael Guntsche +Michael Reneer +Michael Yanovich +Mike Yumatov +Mikhail Korobov +m-r-r +mviera +Nico Di Rocco +Nicolas Duhamel +Nicolas Perriault +Nicolas Steinmetz +Paul Asselin +Pavel Puchkin +Perry Roper +Peter Desmet +Philippe Pepiot +Rachid Belaid +Randall Degges +Ranjhith Kalisamy +Remi Rampin +Rémy HUBSCHER +renhbo +Richard Duivenvoorde +Rogdham +Roman Skvazh +Ronny Pfannschmidt +Rory McCann +Rıdvan Örsvuran +saghul +sam +Samrat Man Singh +Simon Conseil +Simon Liedtke +Skami18 +solsTiCe d'Hiver +Steve Schwarz +Stéphane Bunel +Stéphane Raimbault +Stuart Colville +Talha Mansoor +Tarek Ziade +Thanos Lefteris +Thomas Thurman +Tobias +Tomi Pieviläinen +Trae Blain +Tshepang Lekhonkhobe +Valentin-Costel Hăloiu +Vlad Niculae +William Light +Wladislaw Merezhko +W. Trevor King +Zoresvit diff --git a/TODO b/TODO deleted file mode 100644 index ca29204d..00000000 --- a/TODO +++ /dev/null @@ -1,9 +0,0 @@ -* Add a way to support pictures (see how sphinx makes that) -* Make the program support UTF8-encoded files as input (and later: any encoding?) -* Add status support (draft, published, hidden) -* Add a serve + automatic generation behaviour. -* Recompile only the changed files, not all. -* Add a way to make the coffee (or not) -* Add a sitemap generator. -* read templates from the templates folder per default -* add support of github via ghg import diff --git a/bumpr.rc b/bumpr.rc new file mode 100644 index 00000000..97dbad22 --- /dev/null +++ b/bumpr.rc @@ -0,0 +1,30 @@ +[bumpr] +file = pelican/__init__.py +vcs = git +clean = + python setup.py clean + rm -rf *egg-info build dist +tests = python -m unittest discover +publish = python setup.py sdist bdist_wheel register upload +files = README.rst + +[bump] +unsuffix = true +message = Bump version {version} + +[prepare] +part = patch +suffix = dev +message = Prepare version {version} for next development cycle + +[changelog] +file = docs/changelog.rst +separator = = +bump = {version} ({date:%Y-%m-%d}) +prepare = Next release + +[readthedoc] +url = http://docs.getpelican.com/{tag} + +[commands] +bump = sed -i "" "s/last_stable\s*=.*/last_stable = '{version}'/" docs/conf.py diff --git a/dev_requirements.txt b/dev_requirements.txt index acf01773..a7c10719 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -1,8 +1,15 @@ # Tests -unittest2 mock + # Optional Packages Markdown -BeautifulSoup +BeautifulSoup4 +lxml typogrify -webassets \ No newline at end of file + +# To perform release +bumpr==0.2.0 +wheel + +# For docs theme +sphinx_rtd_theme diff --git a/docs/_static/pelican.gif b/docs/_static/pelican.gif deleted file mode 100644 index d9208590..00000000 Binary files a/docs/_static/pelican.gif and /dev/null differ diff --git a/docs/_static/pelican.png b/docs/_static/pelican.png deleted file mode 100644 index c2d61c88..00000000 Binary files a/docs/_static/pelican.png and /dev/null differ diff --git a/docs/_static/theme_overrides.css b/docs/_static/theme_overrides.css new file mode 100644 index 00000000..83afc78e --- /dev/null +++ b/docs/_static/theme_overrides.css @@ -0,0 +1,12 @@ + +/* override table width restrictions */ +.wy-table-responsive table td, .wy-table-responsive table th { + /* !important prevents the common CSS stylesheets from + overriding this as on RTD they are loaded after this stylesheet */ + white-space: normal !important; +} + +.wy-table-responsive { + overflow: visible !important; +} + diff --git a/docs/_themes/.gitignore b/docs/_themes/.gitignore deleted file mode 100644 index 66b6e4c2..00000000 --- a/docs/_themes/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.pyc -*.pyo -.DS_Store diff --git a/docs/_themes/pelican/layout.html b/docs/_themes/pelican/layout.html deleted file mode 100644 index aa1716aa..00000000 --- a/docs/_themes/pelican/layout.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends "basic/layout.html" %} -{% block header %} - {{ super() }} - {% if pagename == 'index' %} -
- {% endif %} -{% endblock %} -{% block footer %} - {% if pagename == 'index' %} -
- {% endif %} -{% endblock %} -{# do not display relbars #} -{% block relbar1 %}{% endblock %} -{% block relbar2 %} - {% if theme_github_fork %} - Fork me on GitHub - {% endif %} -{% endblock %} -{% block sidebar1 %}{% endblock %} -{% block sidebar2 %}{% endblock %} diff --git a/docs/_themes/pelican/static/pelican.css_t b/docs/_themes/pelican/static/pelican.css_t deleted file mode 100644 index 3cb2a3c1..00000000 --- a/docs/_themes/pelican/static/pelican.css_t +++ /dev/null @@ -1,254 +0,0 @@ -/* - * pelican.css_t - * ~~~~~~~~~~~~ - * - * Sphinx stylesheet -- pelican theme, based on the nature theme - * - * :copyright: Copyright 2011 by Alexis Metaireau. - */ - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: Arial, sans-serif; - font-size: 100%; - background-color: white; - color: #555; - margin: 0; - padding: 0; -} - -div.documentwrapper { - width: 70%; - margin: auto; -} - -div.bodywrapper { - margin: 0 0 0 230px; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.document { -} - -div.body { - background-color: #ffffff; - color: #3E4349; - padding: 0 30px 30px 30px; - font-size: 0.9em; -} - -div.footer { - color: #555; - width: 100%; - padding: 13px 0; - text-align: center; - font-size: 75%; -} - -div.footer a { - color: #444; - text-decoration: underline; -} - -div.related { - background-color: #6BA81E; - line-height: 32px; - color: #fff; - text-shadow: 0px 1px 0 #444; - font-size: 0.9em; -} - -div.related a { - color: #E2F3CC; -} - -div.sphinxsidebar { - font-size: 0.75em; - line-height: 1.5em; -} - -div.sphinxsidebarwrapper{ - padding: 20px 0; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-family: Arial, sans-serif; - color: #222; - font-size: 1.2em; - font-weight: normal; - margin: 0; - padding: 5px 10px; - background-color: #ddd; - text-shadow: 1px 1px 0 white -} - -div.sphinxsidebar h4{ - font-size: 1.1em; -} - -div.sphinxsidebar h3 a { - color: #444; -} - - -div.sphinxsidebar p { - color: #888; - padding: 5px 20px; -} - -div.sphinxsidebar p.topless { -} - -div.sphinxsidebar ul { - margin: 10px 20px; - padding: 0; - color: #000; -} - -div.sphinxsidebar a { - color: #444; -} - -div.sphinxsidebar input { - border: 1px solid #ccc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar input[type=text]{ - margin-left: 20px; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #005B81; - text-decoration: none; -} - -a:hover { - color: #E32E00; - text-decoration: underline; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: Arial, sans-serif; - font-weight: normal; - color: #212224; - margin: 30px 0px 10px 0px; - padding: 5px 0 5px 10px; - text-shadow: 0px 1px 0 white -} - -{% if theme_index_logo %} -div.indexwrapper h1 { - text-indent: -999999px; - background: url({{ theme_index_logo }}) no-repeat center center; - height: {{ theme_index_logo_height }}; -} -{% endif %} -div.body h1 { - border-top: 20px solid white; - margin-top: 0; - font-size: 250%; - text-align: center; -} - -div.body h2 { font-size: 150%; background-color: #C8D5E3; } -div.body h3 { font-size: 120%; background-color: #D8DEE3; } -div.body h4 { font-size: 110%; background-color: #D8DEE3; } -div.body h5 { font-size: 100%; background-color: #D8DEE3; } -div.body h6 { font-size: 100%; background-color: #D8DEE3; } - -a.headerlink { - color: #c60f0f; - font-size: 0.8em; - padding: 0 4px 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - background-color: #c60f0f; - color: white; -} - -div.body p, div.body dd, div.body li { - line-height: 1.5em; -} - -div.admonition p.admonition-title + p { - display: inline; -} - -div.highlight{ - background-color: #111; -} - -div.note { - background-color: #eee; - border: 1px solid #ccc; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; -} - -div.topic { - background-color: #eee; -} - -div.warning { - background-color: #ffe4e4; - border: 1px solid #f66; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre { - padding: 10px; - background-color: #111; - color: #fff; - line-height: 1.2em; - border: 1px solid #C6C9CB; - font-size: 1.1em; - margin: 1.5em 0 1.5em 0; - -webkit-box-shadow: 1px 1px 1px #d8d8d8; - -moz-box-shadow: 1px 1px 1px #d8d8d8; -} - -tt { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ - font-size: 1.1em; - font-family: monospace; -} - -.viewcode-back { - font-family: Arial, sans-serif; -} - -div.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9; -} diff --git a/docs/_themes/pelican/theme.conf b/docs/_themes/pelican/theme.conf deleted file mode 100644 index ffbb7945..00000000 --- a/docs/_themes/pelican/theme.conf +++ /dev/null @@ -1,10 +0,0 @@ -[theme] -inherit = basic -stylesheet = pelican.css -nosidebar = true -pygments_style = fruity - -[options] -index_logo_height = 120px -index_logo = -github_fork = diff --git a/docs/changelog.rst b/docs/changelog.rst index 6cea6d93..52367cec 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,13 +1,143 @@ Release history ############### -3.1 (XXXX-XX-XX) +3.5.0 (2014-11-04) +================== + +* Introduce ``ARTICLE_ORDER_BY`` and ``PAGE_ORDER_BY`` settings to control the + order of articles and pages. +* Include time zone information in dates rendered in templates. +* Expose the reader name in the metadata for articles and pages. +* Add the ability to store static files along with content in the same + directory as articles and pages using ``{attach}`` in the path. +* Prevent Pelican from raising an exception when there are duplicate pieces of + metadata in a Markdown file. +* Introduce the ``TYPOGRIFY_IGNORE_TAGS`` setting to add HTML tags to be ignored + by Typogrify. +* Add the ability to use ``-`` in date formats to strip leading zeros. For + example, ``%-d/%-m/%y`` will now result in the date ``9/8/12``. +* Ensure feed generation is correctly disabled during quickstart configuration. +* Fix ``PAGE_EXCLUDES`` and ``ARTICLE_EXCLUDES`` from incorrectly matching + sub-directories. +* Introduce ``STATIC_EXCLUDE`` setting to add static file excludes. +* Fix an issue when using ``PAGINATION_PATTERNS`` while ``RELATIVE_URLS`` + is enabled. +* Fix feed generation causing links to use the wrong language for month + names when using other locales. +* Fix an issue where the authors list in the simple template wasn't correctly + formatted. +* Fix an issue when parsing non-string URLs from settings. +* Improve consistency of debug and warning messages. + +3.4.0 (2014-07-01) +================== + +* Speed up content generation via new caching mechanism +* Add selective post generation (instead of always building entire site) +* Many documentation improvements, including switching to prettier RtD theme +* Add support for multiple content and plugin paths +* Add ``:modified:`` metadata field to complement ``:date:``. + Used to specify the last date and time an article was updated independently + from the date and time it was published. +* Add support for multiple authors via new ``:authors:`` metadata field +* Watch for changes in static directories when in auto-regeneration mode +* Add filters to limit log output when desired +* Add language support to drafts +* Add ``SLUGIFY_SOURCE`` setting to control how post slugs are generated +* Fix many issues relating to locale and encoding +* Apply Typogrify filter to post summary +* Preserve file metadata (e.g. time stamps) when copying static files to output +* Move AsciiDoc support from Pelican core into separate plugin +* Produce inline links instead of reference-style links when importing content +* Improve handling of ``IGNORE_FILES`` setting behavior +* Properly escape symbol characters in tag names (e.g., ``C++``) +* Minor tweaks for Python 3.4 compatibility +* Add several new signals + +3.3.0 (2013-09-24) +================== + +* Drop Python 3.2 support in favor of Python 3.3 +* Add ``Fabfile`` so Fabric can be used for workflow automation instead of Make +* ``OUTPUT_RETENTION`` setting can be used to preserve metadata (e.g., VCS + data such as ``.hg`` and ``.git``) from being removed from output directory +* Tumblr import +* Improve logic and consistency when cleaning output folder +* Improve documentation versioning and release automation +* Improve pagination flexibility +* Rename signals for better consistency (some plugins may need to be updated) +* Move metadata extraction from generators to readers; metadata extraction no + longer article-specific +* Deprecate ``FILES_TO_COPY`` in favor of ``STATIC_PATHS`` and + ``EXTRA_PATH_METADATA`` +* Summaries in Markdown posts no longer include footnotes +* Remove unnecessary whitespace in output via ``lstrip_blocks`` Jinja parameter +* Move PDF generation from core to plugin +* Replace ``MARKUP`` setting with ``READERS`` +* Add warning if img tag is missing ``alt`` attribute +* Add support for ``{}`` in relative links syntax, besides ``||`` +* Add support for ``{tag}`` and ``{category}`` relative links +* Add a ``content_written`` signal + +3.2.1 and 3.2.2 +=============== + +* Facilitate inclusion in FreeBSD Ports Collection + +3.2 (2013-04-24) ================ +* Support for Python 3! +* Override page save-to location from meta-data (enables using a static page as + the site's home page, for example) +* Time period archives (per-year, per-month, and per-day archives of posts) +* Posterous blog import +* Improve WordPress blog import +* Migrate plugins to separate repository +* Improve HTML parser +* Provide ability to show or hide categories from menu using + ``DISPLAY_CATEGORIES_ON_MENU`` option +* Auto-regeneration can be told to ignore files via ``IGNORE_FILES`` setting +* Improve post-generation feedback to user +* For multilingual posts, use meta-data to designate which is the original + and which is the translation +* Add ``.mdown`` to list of supported Markdown file extensions +* Document-relative URL generation (``RELATIVE_URLS``) is now off by default + +3.1 (2012-12-04) +================ + +* Importer now stores slugs within files by default. This can be disabled with + the ``--disable-slugs`` option. * Improve handling of links to intra-site resources +* Ensure WordPress import adds paragraphs for all types of line endings + in post content +* Decode HTML entities within WordPress post titles on import +* Improve appearance of LinkedIn icon in default theme +* Add GitHub and Google+ social icons support in default theme +* Optimize social icons +* Add ``FEED_ALL_ATOM`` and ``FEED_ALL_RSS`` to generate feeds containing all posts regardless of their language +* Split ``TRANSLATION_FEED`` into ``TRANSLATION_FEED_ATOM`` and ``TRANSLATION_FEED_RSS`` +* Different feeds can now be enabled/disabled individually +* Allow for blank author: if ``AUTHOR`` setting is not set, author won't + default to ``${USER}`` anymore, and a post won't contain any author + information if the post author is empty +* Move LESS and Webassets support from Pelican core to plugin +* The ``DEFAULT_DATE`` setting now defaults to ``None``, which means that + articles won't be generated unless date metadata is specified +* Add ``FILENAME_METADATA`` setting to support metadata extraction from filename +* Add ``gzip_cache`` plugin to compress common text files into a ``.gz`` + file within the same directory as the original file, preventing the server + (e.g. Nginx) from having to compress files during an HTTP call +* Add support for AsciiDoc-formatted content +* Add ``USE_FOLDER_AS_CATEGORY`` setting so that feature can be toggled on/off +* Support arbitrary Jinja template files +* Restore basic functional tests +* New signals: ``generator_init``, ``get_generators``, and + ``article_generate_preread`` 3.0 (2012-08-08) -================== +================ * Refactored the way URLs are handled * Improved the English documentation diff --git a/docs/conf.py b/docs/conf.py index 2a11fe3e..d4efcb38 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,49 +1,80 @@ # -*- coding: utf-8 -*- +from __future__ import unicode_literals import sys, os -sys.path.append(os.path.abspath('..')) +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' -from pelican import __version__, __major__ +sys.path.append(os.path.abspath(os.pardir)) + +from pelican import __version__ # -- General configuration ----------------------------------------------------- templates_path = ['_templates'] -extensions = ['sphinx.ext.autodoc',] +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.ifconfig', 'sphinx.ext.extlinks'] source_suffix = '.rst' master_doc = 'index' -project = u'Pelican' -copyright = u'2010, Alexis Metaireau and contributors' +project = 'Pelican' +copyright = '2014, Alexis Metaireau and contributors' exclude_patterns = ['_build'] -version = __version__ -release = __major__ +release = __version__ +version = '.'.join(release.split('.')[:1]) +last_stable = '3.3.0' +rst_prolog = ''' +.. |last_stable| replace:: :pelican-doc:`{0}` +'''.format(last_stable) + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +extlinks = { + 'pelican-doc': ('http://docs.getpelican.com/%s/', '') +} # -- Options for HTML output --------------------------------------------------- -html_theme_path = ['_themes'] -html_theme = 'pelican' - -html_theme_options = { - 'nosidebar': True, - 'index_logo': 'pelican.png', - 'github_fork': 'getpelican/pelican', -} +html_theme = 'default' +if not on_rtd: + try: + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + except ImportError: + pass html_static_path = ['_static'] # Output file base name for HTML help builder. htmlhelp_basename = 'Pelicandoc' +html_use_smartypants = True + +# If false, no module index is generated. +html_use_modindex = False + +# If false, no index is generated. +html_use_index = False + +# If true, links to the reST sources are added to the pages. +html_show_sourcelink = False + + +def setup(app): + # overrides for wide tables in RTD theme + app.add_stylesheet('theme_overrides.css') # path relative to _static + + # -- Options for LaTeX output -------------------------------------------------- latex_documents = [ - ('index', 'Pelican.tex', u'Pelican Documentation', - u'Alexis Métaireau', 'manual'), + ('index', 'Pelican.tex', 'Pelican Documentation', + 'Alexis Métaireau', 'manual'), ] # -- Options for manual page output -------------------------------------------- man_pages = [ - ('index', 'pelican', u'pelican documentation', - [u'Alexis Métaireau'], 1), - ('pelican-themes', 'pelican-themes', u'A theme manager for Pelican', - [u'Mickaël Raybaud'], 1), - ('themes', 'pelican-theming', u'How to create themes for Pelican', - [u'The Pelican contributors'], 1) + ('index', 'pelican', 'pelican documentation', + ['Alexis Métaireau'], 1), + ('pelican-themes', 'pelican-themes', 'A theme manager for Pelican', + ['Mickaël Raybaud'], 1), + ('themes', 'pelican-theming', 'How to create themes for Pelican', + ['The Pelican contributors'], 1) ] diff --git a/docs/content.rst b/docs/content.rst new file mode 100644 index 00000000..fa65ac5d --- /dev/null +++ b/docs/content.rst @@ -0,0 +1,505 @@ +Writing content +############### + +Articles and pages +================== + +Pelican considers "articles" to be chronological content, such as posts on a +blog, and thus associated with a date. + +The idea behind "pages" is that they are usually not temporal in nature and are +used for content that does not change very often (e.g., "About" or "Contact" +pages). + +.. _internal_metadata: + +File metadata +============= + +Pelican tries to be smart enough to get the information it needs from the +file system (for instance, about the category of your articles), but some +information you need to provide in the form of metadata inside your files. + +If you are writing your content in reStructuredText format, you can provide +this metadata in text files via the following syntax (give your file the +``.rst`` extension):: + + My super title + ############## + + :date: 2010-10-03 10:20 + :modified: 2010-10-04 18:40 + :tags: thats, awesome + :category: yeah + :slug: my-super-post + :authors: Alexis Metaireau, Conan Doyle + :summary: Short version for index and feeds + +Pelican implements an extension to reStructuredText to enable support for the +``abbr`` HTML tag. To use it, write something like this in your post:: + + This will be turned into :abbr:`HTML (HyperText Markup Language)`. + +You can also use Markdown syntax (with a file ending in ``.md``, +``.markdown``, ``.mkd``, or ``.mdown``). Markdown generation requires that you +first explicitly install the ``Markdown`` package, which can be done via ``pip +install Markdown``. + +Pelican also supports `Markdown Extensions`_, which might have to be installed +separately if they are not included in the default ``Markdown`` package and can +be configured and loaded via the ``MD_EXTENSIONS`` setting. + +Metadata syntax for Markdown posts should follow this pattern:: + + Title: My super title + Date: 2010-12-03 10:20 + Modified: 2010-12-05 19:30 + Category: Python + Tags: pelican, publishing + Slug: my-super-post + Authors: Alexis Metaireau, Conan Doyle + Summary: Short version for index and feeds + + This is the content of my super blog post. + +Readers for additional formats (such as AsciiDoc_) are available via plugins. +Refer to `pelican-plugins`_ repository for those. + +Pelican can also process HTML files ending in ``.html`` and ``.htm``. Pelican +interprets the HTML in a very straightforward manner, reading metadata from +``meta`` tags, the title from the ``title`` tag, and the body out from the +``body`` tag:: + + + + My super title + + + + + + + + + This is the content of my super blog post. + + + +With HTML, there is one simple exception to the standard metadata: ``tags`` can +be specified either via the ``tags`` metadata, as is standard in Pelican, or +via the ``keywords`` metadata, as is standard in HTML. The two can be used +interchangeably. + +Note that, aside from the title, none of this article metadata is mandatory: +if the date is not specified and ``DEFAULT_DATE`` is set to ``fs``, 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``. 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``. When parsing dates given in the page metadata, Pelican supports +the W3C's `suggested subset ISO 8601`__. + +.. note:: + + When experimenting with different settings (especially the metadata + ones) caching may interfere and the changes may not be visible. In + such cases disable caching with ``LOAD_CONTENT_CACHE = False`` or + use the ``--ignore-cache`` command-line switch. + +__ `W3C ISO 8601`_ + +``modified`` should be last time you updated the article, and defaults to ``date`` if not specified. +Besides you can show ``modified`` in the templates, feed entries in feed readers will be updated automatically +when you set ``modified`` to the current date after you modified your article. + +``authors`` is a comma-separated list of article authors. If there's only one author you +can use ``author`` field. + +If you do not explicitly specify summary metadata for a given post, the +``SUMMARY_MAX_LENGTH`` setting can be used to specify how many words from the +beginning of an article are used as the summary. + +You can also extract any metadata from the filename through a regular +expression to be set in the ``FILENAME_METADATA`` setting. All named groups +that are matched will be set in the metadata object. The default value for the +``FILENAME_METADATA`` setting will only extract the date from the filename. For +example, if you would like to extract both the date and the slug, you could set +something like: ``'(?P\d{4}-\d{2}-\d{2})_(?P.*)'`` + +Please note that the metadata available inside your files takes precedence over +the metadata extracted from the filename. + +Pages +===== + +If you create a folder named ``pages`` inside the content folder, all the +files in it will be used to generate static pages, such as **About** or +**Contact** pages. (See example filesystem layout below.) + +You can use the ``DISPLAY_PAGES_ON_MENU`` setting to control whether all those +pages are displayed in the primary navigation menu. (Default is ``True``.) + +If you want to exclude any pages from being linked to or listed in the menu +then add a ``status: hidden`` attribute to its metadata. This is useful for +things like making error pages that fit the generated theme of your site. + +.. _ref-linking-to-internal-content: + +Linking to internal content +=========================== + +From Pelican 3.1 onwards, it is now possible to specify intra-site links to +files in the *source content* hierarchy instead of files in the *generated* +hierarchy. This makes it easier to link from the current post to other content +that may be sitting alongside that post (instead of having to determine where +the other content will be placed after site generation). + +To link to internal content (files in the ``content`` directory), use the +following syntax for the link target: ``{filename}path/to/file`` + +For example, a Pelican project might be structured like this:: + + website/ + ├── content + │   ├── category/ + │   │   └── article1.rst + │   ├── article2.md + │ └── pages + │      └── about.md + └── pelican.conf.py + +In this example, ``article1.rst`` could look like this:: + + The first article + ################# + + :date: 2012-12-01 10:02 + + See below intra-site link examples in reStructuredText format. + + `a link relative to the current file <{filename}../article2.md>`_ + `a link relative to the content root <{filename}/article2.md>`_ + +and ``article2.md``:: + + Title: The second article + Date: 2012-12-01 10:02 + + See below intra-site link examples in Markdown format. + + [a link relative to the current file]({filename}category/article1.rst) + [a link relative to the content root]({filename}/category/article1.rst) + +Linking to static files +----------------------- + +Linking to non-article or non-page content uses the same ``{filename}`` syntax +as described above. It is important to remember that those files will not be +copied to the output directory unless the source directories containing them +are included in the ``STATIC_PATHS`` setting of the project's ``pelicanconf.py`` +file. Pelican's default configuration includes the ``images`` directory for +this, but others must be added manually. Forgetting to do so will result in +broken links. + +For example, a project's content directory might be structured like this:: + + content + ├── images + │   └── han.jpg + ├── pdfs + │   └── menu.pdf + └── pages +    └── test.md + +``test.md`` would include:: + + ![Alt Text]({filename}/images/han.jpg) + [Our Menu]({filename}/pdfs/menu.pdf) + +``pelicanconf.py`` would include:: + + STATIC_PATHS = ['images', 'pdfs'] + +Site generation would then copy ``han.jpg`` to ``output/images/han.jpg``, +``menu.pdf`` to ``output/pdfs/menu.pdf``, and write the appropriate links +in ``test.md``. + +Mixed content in the same directory +----------------------------------- + +Starting with Pelican 3.5, static files can safely share a source directory with +page source files, without exposing the page sources in the generated site. +Any such directory must be added to both ``STATIC_PATHS`` and ``PAGE_PATHS`` +(or ``STATIC_PATHS`` and ``ARTICLE_PATHS``). Pelican will identify and process +the page source files normally, and copy the remaining files as if they lived +in a separate directory reserved for static files. + +Note: Placing static and content source files together in the same source +directory does not guarantee that they will end up in the same place in the +generated site. The easiest way to do this is by using the ``{attach}`` link +syntax (described below). Alternatively, the ``STATIC_SAVE_AS``, +``PAGE_SAVE_AS``, and ``ARTICLE_SAVE_AS`` settings (and the corresponding +``*_URL`` settings) can be configured to place files of different types +together, just as they could in earlier versions of Pelican. + +Attaching static files +---------------------- + +Starting with Pelican 3.5, static files can be "attached" to a page or article +using this syntax for the link target: ``{attach}path/to/file`` This works +like the ``{filename}`` syntax, but also relocates the static file into the +linking document's output directory. If the static file originates from a +subdirectory beneath the linking document's source, that relationship will be +preserved on output. Otherwise, it will become a sibling of the linking +document. + +This only works for linking to static files, and only when they originate from +a directory included in the ``STATIC_PATHS`` setting. + +For example, a project's content directory might be structured like this:: + + content + ├── blog + │   ├── icons + │   │   └── icon.png + │   ├── photo.jpg + │   └── testpost.md + └── downloads + └── archive.zip + +``pelicanconf.py`` would include:: + + PATH = 'content' + STATIC_PATHS = ['blog', 'downloads'] + ARTICLE_PATHS = ['blog'] + ARTICLE_SAVE_AS = '{date:%Y}/{slug}.html' + ARTICLE_URL = '{date:%Y}/{slug}.html' + +``testpost.md`` would include:: + + Title: Test Post + Category: test + Date: 2014-10-31 + + ![Icon]({attach}icons/icon.png) + ![Photo]({attach}photo.jpg) + [Downloadable File]({attach}/downloads/archive.zip) + +Site generation would then produce an output directory structured like this:: + + output + └── 2014 + ├── archive.zip + ├── icons + │   └── icon.png + ├── photo.jpg + └── test-post.html + +Notice that all the files linked using ``{attach}`` ended up in or beneath +the article's output directory. + +If a static file is linked multiple times, the relocating feature of +``{attach}`` will only work in the first of those links to be processed. +After the first link, Pelican will treat ``{attach}`` like ``{filename}``. +This avoids breaking the already-processed links. + +**Be careful when linking to a file from multiple documents:** +Since the first link to a file finalizes its location and Pelican does +not define the order in which documents are processed, using ``{attach}`` on a +file linked by multiple documents can cause its location to change from one +site build to the next. (Whether this happens in practice will depend on the +operating system, file system, version of Pelican, and documents being added, +modified, or removed from the project.) Any external sites linking to the +file's old location might then find their links broken. **It is therefore +advisable to use {attach} only if you use it in all links to a file, and only +if the linking documents share a single directory.** Under these conditions, +the file's output location will not change in future builds. In cases where +these precautions are not possible, consider using ``{filename}`` links instead +of ``{attach}``, and letting the file's location be determined by the project's +``STATIC_SAVE_AS`` and ``STATIC_URL`` settings. (Per-file ``save_as`` and +``url`` overrides can still be set in ``EXTRA_PATH_METADATA``.) + +Linking to tags and categories +------------------------------ + +You can link to tags and categories using the ``{tag}tagname`` and +``{category}foobar`` syntax. + +Deprecated internal link syntax +------------------------------- + +To remain compatible with earlier versions, Pelican still supports vertical bars +(``||``) in addition to curly braces (``{}``) for internal links. For example: +``|filename|an_article.rst``, ``|tag|tagname``, ``|category|foobar``. +The syntax was changed from ``||`` to ``{}`` to avoid collision with Markdown +extensions or reST directives. Support for the old syntax may eventually be +removed. + + +Importing an existing site +========================== + +It is possible to import your site from WordPress, Tumblr, Dotclear, and RSS +feeds using a simple script. See :ref:`import`. + +Translations +============ + +It is possible to translate articles. To do so, you need to add a ``lang`` meta +attribute to your articles/pages and set a ``DEFAULT_LANG`` setting (which is +English [en] by default). With those settings in place, only articles with the +default language will be listed, and each article will be accompanied by a list +of available translations for that article. + +.. note:: + + This core Pelican functionality does not create sub-sites + (e.g. ``example.com/de``) with translated templates for each + language. For such advanced functionality the `i18n_subsites + plugin`_ can be used. + +Pelican uses the article's URL "slug" to determine if two or more articles are +translations of one another. The slug can be set manually in the file's +metadata; if not set explicitly, Pelican will auto-generate the slug from the +title of the article. + +Here is an example of two articles, one in English and the other in French. + +The English article:: + + Foobar is not dead + ################## + + :slug: foobar-is-not-dead + :lang: en + + That's true, foobar is still alive! + +And the French version:: + + Foobar n'est pas mort ! + ####################### + + :slug: foobar-is-not-dead + :lang: fr + + Oui oui, foobar est toujours vivant ! + +Post content quality notwithstanding, you can see that only item in common +between the two articles is the slug, which is functioning here as an +identifier. If you'd rather not explicitly define the slug this way, you must +then instead ensure that the translated article titles are identical, since the +slug will be auto-generated from the article title. + +If you do not want the original version of one specific article to be detected +by the ``DEFAULT_LANG`` setting, use the ``translation`` metadata to specify +which posts are translations:: + + Foobar is not dead + ################## + + :slug: foobar-is-not-dead + :lang: en + :translation: true + + That's true, foobar is still alive! + + +.. _internal_pygments_options: + +Syntax highlighting +=================== + +Pelican is able to provide colorized syntax highlighting for your code blocks. +To do so, you have to use the following conventions inside your content files. + +For reStructuredText, use the code-block directive:: + + .. code-block:: identifier + + + +For Markdown, include the language identifier just above the code block, +indenting both the identifier and code:: + + A block of text. + + :::identifier + + +The specified identifier (e.g. ``python``, ``ruby``) should be one that +appears on the `list of available lexers `_. + +When using reStructuredText the following options are available in the +code-block directive: + +============= ============ ========================================= +Option Valid values Description +============= ============ ========================================= +anchorlinenos N/A If present wrap line numbers in tags. +classprefix string String to prepend to token class names +hl_lines numbers List of lines to be highlighted. +lineanchors string Wrap each line in an anchor using this + string and -linenumber. +linenos string If present or set to "table" output line + numbers in a table, if set to + "inline" output them inline. "none" means + do not output the line numbers for this + table. +linenospecial number If set every nth line will be given the + 'special' css class. +linenostart number Line number for the first line. +linenostep number Print every nth line number. +lineseparator string String to print between lines of code, + '\n' by default. +linespans string Wrap each line in a span using this and + -linenumber. +nobackground N/A If set do not output background color for + the wrapping element +nowrap N/A If set do not wrap the tokens at all. +tagsfile string ctags file to use for name definitions. +tagurlformat string format for the ctag links. +============= ============ ========================================= + +Note that, depending on the version, your Pygments module might not have +all of these options available. Refer to the *HtmlFormatter* section of the +`Pygments documentation `_ for more +details on each of the options. + +For example, the following code block enables line numbers, starting at 153, +and prefixes the Pygments CSS classes with *pgcss* to make the names +more unique and avoid possible CSS conflicts:: + + .. code-block:: identifier + :classprefix: pgcss + :linenos: table + :linenostart: 153 + + + +It is also possible to specify the ``PYGMENTS_RST_OPTIONS`` variable in your +Pelican settings file to include options that will be automatically applied to +every code block. + +For example, if you want to have line numbers displayed for every code block +and a CSS prefix you would set this variable to:: + + PYGMENTS_RST_OPTIONS = {'classprefix': 'pgcss', 'linenos': 'table'} + +If specified, settings for individual code blocks will override the defaults in +your settings file. + +Publishing drafts +================= + +If you want to publish an article as a draft (for friends to review before +publishing, for example), you can add a ``Status: draft`` attribute to its +metadata. That article will then be output to the ``drafts`` folder and not +listed on the index page nor on any category or tag page. + +.. _W3C ISO 8601: http://www.w3.org/TR/NOTE-datetime +.. _AsciiDoc: http://www.methods.co.nz/asciidoc/ +.. _pelican-plugins: http://github.com/getpelican/pelican-plugins +.. _Markdown Extensions: http://pythonhosted.org/Markdown/extensions/ +.. _i18n_subsites plugin: http://github.com/getpelican/pelican-plugins/tree/master/i18n_subsites diff --git a/docs/contribute.rst b/docs/contribute.rst index 0820d5c3..2962ddb1 100644 --- a/docs/contribute.rst +++ b/docs/contribute.rst @@ -1,29 +1,34 @@ -How to contribute? -################### -There are many ways to contribute to Pelican. You can enhance the -documentation, add missing features, and fix bugs (or just report them). +Contributing and feedback guidelines +#################################### -Don't hesitate to fork and make a pull request on GitHub. When doing so, please -create a new feature branch as opposed to making your commits in the master -branch. +There are many ways to contribute to Pelican. You can improve the +documentation, add missing features, and fix bugs (or just report them). You +can also help out by reviewing and commenting on +`existing issues `_. + +Don't hesitate to fork Pelican and submit an issue or pull request on GitHub. +When doing so, please adhere to the following guidelines. + +.. include:: ../CONTRIBUTING.rst Setting up the development environment ====================================== -You're free to set up your development environment any way you like. Here is a -way using the `virtualenv `_ and `virtualenvwrapper -`_ tools. If you don't -have them, you can install these both of these packages via:: +While there are many ways to set up one's development environment, following +is a method that uses `virtualenv `_. If you don't +have ``virtualenv`` installed, you can install it via:: - $ pip install virtualenvwrapper + $ pip install virtualenv Virtual environments allow you to work on Python projects which are isolated from one another so you can use different packages (and package versions) with different projects. -To create a virtual environment, use the following syntax:: +To create and activate a virtual environment, use the following syntax:: - $ mkvirtualenv pelican + $ virtualenv ~/virtualenvs/pelican + $ cd ~/virtualenvs/pelican + $ . bin/activate To clone the Pelican source:: @@ -38,32 +43,164 @@ To install Pelican and its dependencies:: $ python setup.py develop +Or using ``pip``:: + + $ pip install -e . + +Building the docs +================= + +If you make changes to the documentation, you should preview your changes +before committing them:: + + $ pip install sphinx + $ cd src/pelican/docs + $ make html + +Open ``_build/html/index.html`` in your browser to preview the documentation. + Running the test suite ====================== Each time you add a feature, there are two things to do regarding tests: -checking that the existing tests pass, and adding tests for the new feature +check that the existing tests pass, and add tests for the new feature or bugfix. -The tests live in "pelican/tests" and you can run them using the -"discover" feature of unittest2:: +The tests live in ``pelican/tests`` and you can run them using the +"discover" feature of ``unittest``:: - $ unit2 discover + $ python -m unittest discover -If you have made changes that affect the output of a Pelican-generated weblog, -then you should update the output used by functional tests. -To do so, you can use the following two commands:: +After making your changes and running the tests, you may see a test failure +mentioning that "some generated files differ from the expected functional tests +output." If you have made changes that affect the HTML output generated by +Pelican, and the changes to that output are expected and deemed correct given +the nature of your changes, then you should update the output used by the +functional tests. To do so, you can use the following two commands:: - $ LC_ALL="C" pelican -o tests/output/custom/ -s samples/pelican.conf.py \ + $ LC_ALL=en_US.utf8 pelican -o pelican/tests/output/custom/ \ + -s samples/pelican.conf.py samples/content/ + $ LC_ALL=fr_FR.utf8 pelican -o pelican/tests/output/custom_locale/ \ + -s samples/pelican.conf_FR.py samples/content/ + $ LC_ALL=en_US.utf8 pelican -o pelican/tests/output/basic/ \ samples/content/ - $ LC_ALL="C" USER="Dummy Author" pelican -o tests/output/basic/ samples/content/ -Coding standards -================ +Testing on Python 2 and 3 +------------------------- -Try to respect what is described in the `PEP8 specification -`_ when providing patches. This can be -eased via the `pep8 `_ or `flake8 -`_ tools, the latter of which in -particular will give you some useful hints about ways in which the -code/formatting can be improved. +Testing on Python 3 currently requires some extra steps: installing +Python 3-compatible versions of dependent packages and plugins. + +Tox_ is a useful tool to run tests on both versions. It will install the +Python 3-compatible version of dependent packages. + +.. _Tox: http://testrun.org/tox/latest/ + +Python 3 development tips +========================= + +Here are some tips that may be useful when doing some code for both Python 2.7 +and Python 3 at the same time: + +- Assume every string and literal is unicode (import unicode_literals): + + - Do not use prefix ``u'``. + - Do not encode/decode strings in the middle of sth. Follow the code to the + source (or target) of a string and encode/decode at the first/last possible + point. + - In other words, write your functions to expect and to return unicode. + - Encode/decode strings if e.g. the source is a Python function that is known + to handle this badly, e.g. strftime() in Python 2. + +- Use new syntax: print function, "except ... *as* e" (not comma) etc. +- Refactor method calls like ``dict.iteritems()``, ``xrange()`` etc. in a way + that runs without code change in both Python versions. +- Do not use magic method ``__unicode()__`` in new classes. Use only ``__str()__`` + and decorate the class with ``@python_2_unicode_compatible``. +- Do not start int literals with a zero. This is a syntax error in Py3k. +- Unfortunately I did not find an octal notation that is valid in both + Pythons. Use decimal instead. +- use six, e.g.: + + - ``isinstance(.., basestring) -> isinstance(.., six.string_types)`` + - ``isinstance(.., unicode) -> isinstance(.., six.text_type)`` + +- ``setlocale()`` in Python 2 bails when we give the locale name as unicode, + and since we are using ``from __future__ import unicode_literals``, we do + that everywhere! As a workaround, I enclosed the localename with ``str()``; + in Python 2 this casts the name to a byte string, in Python 3 this should do + nothing, because the locale name already had been unicode. + +- Kept range() almost everywhere as-is (2to3 suggests list(range())), just + changed it where I felt necessary. + +- Changed xrange() back to range(), so it is valid in both Python versions. + + +Logging tips +============ + +Try to use logging with appropriate levels. + +For logging messages that are not repeated, use the usual Python way:: + + # at top of file + import logging + logger = logging.getLogger(__name__) + + # when needed + logger.warning("A warning with %s formatting", arg_to_be_formatted) + +Do not format log messages yourself. Use ``%s`` formatting in messages and pass +arguments to logger. This is important, because Pelican logger will preprocess +some arguments (like Exceptions) for Py2/Py3 compatibility. + +Limiting extraneous log messages +-------------------------------- + +If the log message can occur several times, you may want to limit the log to +prevent flooding. In order to do that, use the ``extra`` keyword argument for +the logging message in the following format:: + + logger.warning("A warning with %s formatting", arg_to_be_formatted, + extra={'limit_msg': 'A generic message for too many warnings'}) + +Optionally, you can also set ``'limit_args'`` as a tuple of arguments in +``extra`` dict if your generic message needs formatting. + +Limit is set to ``5``, i.e, first four logs with the same ``'limit_msg'`` are +outputted normally but the fifth one will be logged using +``'limit_msg'`` (and ``'limit_args'`` if present). After the fifth, +corresponding log messages will be ignored. + +For example, if you want to log missing resources, use the following code:: + + for resource in resources: + if resource.is_missing: + logger.warning( + 'The resource %s is missing', resource.name, + extra={'limit_msg': 'Other resources were missing'}) + +The log messages will be displayed as follows:: + + WARNING: The resource prettiest_cat.jpg is missing + WARNING: The resource best_cat_ever.jpg is missing + WARNING: The resource cutest_cat.jpg is missing + WARNING: The resource lolcat.jpg is missing + WARNING: Other resources were missing + + +Outputting traceback in the logs +-------------------------------- + +If you're logging inside an ``except`` block, you may want to provide the +traceback information as well. You can do that by setting ``exc_info`` keyword +argument to ``True`` during logging. However, doing so by default can be +undesired because tracebacks are long and can be confusing to regular users. +Try to limit them to ``--debug`` mode like the following:: + + try: + some_action() + except Exception as e: + logger.error('Exception occurred: %s', e, + exc_info=settings.get('DEBUG', False)) diff --git a/docs/faq.rst b/docs/faq.rst index e76bea6a..c749c262 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -1,52 +1,63 @@ Frequently Asked Questions (FAQ) ################################ -Here is a summary of the frequently asked questions for Pelican. +Here are some frequently asked questions about Pelican. What's the best way to communicate a problem, question, or suggestion? ====================================================================== -If you have a problem, question, or suggestion, please start by striking up a -conversation on `#pelican on Freenode `_. -Those who don't have an IRC client handy can jump in immediately via -`IRC webchat `_. Because -of differing time zones, you may not get an immediate response to your question, -but please be patient and stay logged into IRC — someone will almost always -respond. - -If you are unable to resolve your issue or if you have a feature request, please -refer to the `issue tracker `_. +Please read our :doc:`feedback guidelines `. 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. +There are several ways to help out. First, you can report any Pelican +suggestions or problems you might have via IRC or the `issue tracker +`_. If submitting an issue +report, please first check the existing issue list (both open and closed) in +order to avoid submitting a duplicate issue. If you want to contribute, please fork `the git repository `_, create a new feature branch, make -your changes, and issue a pull request. Someone will review your changes as soon -as possible. Please refer to the :doc:`How to Contribute ` section -for more details. +your changes, and issue a pull request. Someone will review your changes as +soon as possible. Please refer to the :doc:`How to Contribute ` +section for more details. You can also contribute by creating themes and improving the documentation. Is it mandatory to have a configuration file? ============================================= -No, it's not. Configuration files are just an easy way to configure Pelican. +Configuration files are optional and are just an easy way to configure Pelican. For basic operations, it's possible to specify options while invoking Pelican via the command line. See ``pelican --help`` for more information. +Changes to the setting file take no effect +========================================== + +When experimenting with different settings (especially the metadata +ones) caching may interfere and the changes may not be visible. In +such cases disable caching with ``LOAD_CONTENT_CACHE = False`` or +use the ``--ignore-cache`` command-line switch. + I'm creating my own theme. How do I use Pygments for syntax highlighting? ========================================================================= Pygments adds some classes to the generated content. These classes are used by themes to style code syntax highlighting via CSS. Specifically, you can -customize the appearance of your syntax highlighting via the ``.codehilite pre`` +customize the appearance of your syntax highlighting via the ``.highlight pre`` class in your theme's CSS file. To see how various styles can be used to render -Django code, for example, you can use the demo `on the project website -`_. +Django code, for example, use the style selector drop-down at top-right on the +`Pygments project demo site `_. + +You can use the following example commands to generate a starting CSS file from +a Pygments built-in style (in this case, "monokai") and then copy the generated +CSS file to your new theme:: + + pygmentize -S monokai -f html -a .highlight > pygment.css + cp pygment.css path/to/theme/static/css/ + +Don't forget to import your ``pygment.css`` file from your main CSS file. How do I create my own theme? ============================== @@ -54,18 +65,18 @@ How do I create my own theme? Please refer to :ref:`theming-pelican`. I want to use Markdown, but I got an error. -=========================================== +========================================================================== -Markdown is not a hard dependency for Pelican, so you will need to explicitly -install it. You can do so by typing:: +If you try to generate Markdown content without first installing the Markdown +library, may see a message that says ``No valid files found in content``. +Markdown is not a hard dependency for Pelican, so if you have content in +Markdown format, you will need to explicitly install the Markdown library. +You can do so by typing the following command, prepending ``sudo`` if +permissions require it:: - $ (sudo) pip install markdown + pip install markdown -In case you don't have pip installed, consider installing it via:: - - $ (sudo) easy_install pip - -Can I use arbitrary meta-data in my templates? +Can I use arbitrary metadata in my templates? ============================================== Yes. For example, to include a modified date in a Markdown post, one could @@ -73,56 +84,160 @@ include the following at the top of the article:: Modified: 2012-08-08 -That meta-data can then be accessed in the template:: +For reStructuredText, this metadata should of course be prefixed with a colon:: + + :Modified: 2012-08-08 + +This metadata can then be accessed in templates such as ``article.html`` via:: {% if article.modified %} Last modified: {{ article.modified }} {% endif %} +If you want to include metadata in templates outside the article context (e.g., +``base.html``), the ``if`` statement should instead be:: + + {% if article and article.modified %} + How do I assign custom templates on a per-page basis? ===================================================== -It's as simple as adding an extra line of metadata to any pages or articles you -want to have its own template. +It's as simple as adding an extra line of metadata to any page or article that +you want to have its own template. For example, this is how it would be handled +for content in reST format:: :template: template_name -Then just make sure to have the template installed in to your theme as -``template_name.html``. +For content in Markdown format:: + + Template: template_name + +Then just make sure your theme contains the relevant template file (e.g. +``template_name.html``). + +How can I override the generated URL of a specific page or article? +=================================================================== + +Include ``url`` and ``save_as`` metadata in any pages or articles that you want +to override the generated URL. Here is an example page in reST format:: + + Override url/save_as page + ######################### + + :url: override/url/ + :save_as: override/url/index.html + +With this metadata, the page will be written to ``override/url/index.html`` +and Pelican will use url ``override/url/`` to link to this page. + +How can I use a static page as my home page? +============================================ + +The override feature mentioned above can be used to specify a static page as +your home page. The following Markdown example could be stored in +``content/pages/home.md``:: + + Title: Welcome to My Site + URL: + save_as: index.html + + Thank you for visiting. Welcome! + +If the original blog index is still wanted, it can then be saved in a +different location by setting ``INDEX_SAVE_AS = 'blog_index.html`` for +the ``''index'`` direct template. What if I want to disable feed generation? ========================================== -To disable all feed generation set ``FEED_ATOM`` and ``FEED_RSS`` to ``None`` in -your settings. Please note ``None`` and ``''`` are not the same thing. The -word ``None`` should not be surrounded by quotes. +To disable feed generation, all feed settings should be set to ``None``. +All but three feed settings already default to ``None``, so if you want to +disable all feed generation, you only need to specify the following settings:: + + FEED_ALL_ATOM = None + CATEGORY_FEED_ATOM = None + TRANSLATION_FEED_ATOM = None + AUTHOR_FEED_ATOM = None + AUTHOR_FEED_RSS = None + +The word ``None`` should not be surrounded by quotes. Please note that ``None`` +and ``''`` are not the same thing. I'm getting a warning about feeds generated without SITEURL being set properly ============================================================================== -`RSS and Atom feeds require all URLs and links in them to be absolute +`RSS and Atom feeds require all URL links to be absolute `_. -In order to properly generate all URLs properly in Pelican you will need to set -``SITEURL`` to the full path of your blog. When using ``make html`` and the -default Makefile provided by the `pelican-quickstart` bootstrap script to test -build your site, it's normal to see this warning since ``SITEURL`` is -deliberately left undefined. If configured properly no other ``make`` commands -should result in this warning. +In order to properly generate links in Pelican you will need to set ``SITEURL`` +to the full path of your site. -Feeds are still generated when this warning is displayed but may not validate. +Feeds are still generated when this warning is displayed, but links within may +be malformed and thus the feed may not validate. -My feeds are broken since I upgraded to Pelican 3.0 +My feeds are broken since I upgraded to Pelican 3.x =================================================== Starting in 3.0, some of the FEED setting names were changed to more explicitly refer to the Atom feeds they inherently represent (much like the FEED_RSS -setting names). Here is an exact list of the renamed setting names:: +setting names). Here is an exact list of the renamed settings:: FEED -> FEED_ATOM TAG_FEED -> TAG_FEED_ATOM CATEGORY_FEED -> CATEGORY_FEED_ATOM -Older 2.x themes that referenced the old setting names may not link properly. -In order to rectify this, please update your theme for compatibility with 3.0+ -by changing the relevant values in your template files. For an example of -complete feed headers and usage please check out the ``simple`` theme. +Starting in 3.1, the new feed ``FEED_ALL_ATOM`` has been introduced: this +feed will aggregate all posts regardless of their language. This setting +generates ``'feeds/all.atom.xml'`` by default and ``FEED_ATOM`` now defaults to +``None``. The following feed setting has also been renamed:: + + TRANSLATION_FEED -> TRANSLATION_FEED_ATOM + +Older themes that referenced the old setting names may not link properly. +In order to rectify this, please update your theme for compatibility by changing +the relevant values in your template files. For an example of complete feed +headers and usage please check out the ``simple`` theme. + +Is Pelican only suitable for blogs? +=================================== + +No. Pelican can be easily configured to create and maintain any type of static site. +This may require a little customization of your theme and Pelican configuration. +For example, if you are building a launch site for your product and do not need +tags on your site, you could remove the relevant HTML code from your theme. +You can also disable generation of tag-related pages via:: + + TAGS_SAVE_AS = '' + TAG_SAVE_AS = '' + +Why does Pelican always write all HTML files even with content caching enabled? +=============================================================================== + +In order to reliably determine whether the HTML output is different +before writing it, a large part of the generation environment +including the template contexts, imported plugins, etc. would have to +be saved and compared, at least in the form of a hash (which would +require special handling of unhashable types), because of all the +possible combinations of plugins, pagination, etc. which may change in +many different ways. This would require a lot more processing time +and memory and storage space. Simply writing the files each time is a +lot faster and a lot more reliable. + +However, this means that the modification time of the files changes +every time, so a ``rsync`` based upload will transfer them even if +their content hasn't changed. A simple solution is to make ``rsync`` +use the ``--checksum`` option, which will make it compare the file +checksums in a much faster way than Pelican would. + +When only several specific output files are of interest (e.g. when +working on some specific page or the theme templates), the +`WRITE_SELECTED` option may help, see +:ref:`writing_only_selected_content`. + +How to process only a subset of all articles? +============================================= + +It is often useful to process only e.g. 10 articles for debugging +purposes. This can be achieved by explicitly specifying only the +filenames of those articles in ``ARTICLE_PATHS``. A list of such +filenames could be found using a command similar to ``cd content; +find -name '*.md' | head -n 10``. diff --git a/docs/fr/astuces.rst b/docs/fr/astuces.rst deleted file mode 100644 index 3f9a3987..00000000 --- a/docs/fr/astuces.rst +++ /dev/null @@ -1,20 +0,0 @@ -Trucs et astuces pour Pelican -############################# - -Personnaliser l'url d'un article pour Pelican -============================================= - -Par défaut, quand vous créez un article ayant pour titre *Mon article pour Pelican*, -l'url par défaut devient *mon-article-pour-pelican.html*. Cependant, il est possible -de modifier cela en utilisant la technique utilisée pour les traductions d'article, -c'est à dire le paramètre *:slug:* :: - - Mon article pour Pelican - ######################## - - :date: 2011-01-31 11:05 - :slug: super-article-pour-pelican - - bla, bla, bla … - -En prenant cet exemple ci dessus, votre url deviendra *super-article-pour-pelican.html* diff --git a/docs/fr/bases.rst b/docs/fr/bases.rst deleted file mode 100644 index 7a6fd118..00000000 --- a/docs/fr/bases.rst +++ /dev/null @@ -1,58 +0,0 @@ -Les bases de Pelican -#################### - -Créer son premier article -========================= - -Pour créer notre premier article, nous allons éditer un fichier, par exemple premier_article.rst :: - - Premier article pour Pelican - ############################ - :author: Guillaume - :date: 2011-01-08 10:20 - :category: GNU-Linux - :tags: tutoriel, git - Ceci est un tutoriel pour configurer git. - Bla, bla, bla .... - -Maintenant que ce fichier est créé, on va lancer la création du blog :: - - pelican . - -Vous aller obtenir une sortie comme celle ci — $PATH représente le dossier où vous -avez créé votre article :: - - [ok] writing $PATH/output/feeds/all.atom.xml - [ok] writing $PATH/output/feeds/GNU/Linux.atom.xml - [ok] writing $PATH/output/feeds/all-en.atom.xml - [ok] writing $PATH/output/premier-article-pour-pelican.html - [ok] writing $PATH/output/index.html - [ok] writing $PATH/output/tags.html - [ok] writing $PATH/output/categories.html - [ok] writing $PATH/output/archives.html - [ok] writing $PATH/output/tag/tutoriel.html - [ok] writing $PATH/output/tag/git.html - [ok] writing $PATH/output/category/GNU-Linux.html - - -Première analyse -================ - -Nous allons décortiquer un peu tout ça ensemble. - -* Un dossier output/ a été créé pour y mettre le fichiers xml et html du blog. -* Dans le dossier feeds/, nous retrouvons les différents flux de syndication. -* Le fichier de l’article et la page principale du blog a été généré. -* Le répertoire tag/ propose une page par tag. -* La page correspondant à la catégorie est générée dans le répertoire category/ - -Si vous ouvrez le fichier index.html — ou un autre — avec votre navigateur, vous -remarquerez que : - -* Le thème utilisé par défaut est notmyidea -* Le nom du blog est A Pelican Blog. - -Bien évidemment, il y a des paramètres de base que l’on peut modifier pour mettre -un peu tout ça à sa sauce. C’est ce que nous allons voir au travers du fichier de configuration. - - diff --git a/docs/fr/configuration.rst b/docs/fr/configuration.rst deleted file mode 100644 index abfc7ef5..00000000 --- a/docs/fr/configuration.rst +++ /dev/null @@ -1,159 +0,0 @@ -Fichier de configuration -************************ - -On va créer un fichier de configuration que l’on va appeler **settings.py**. On peut -utiliser Pelican sans faire ce fichier, mais il faudrait à chaque fois passer les paramètres -en ligne de commande. Et comme il va nous servir à faire d’autres choses bien utile, -autant l’appréhender de suite. Cependant, nous n’allons voir que la base pour l’instant. - -Paramètres de base -================== - -AUTHOR : - Désigne l’auteur par défaut ; - -DEFAULT_CATEGORY : - La catégorie par défaut des articles. Si ce paramètre n’est - pas documenté, il prendra la valeur misc — pour miscellaneous (divers en français) ; - -SITENAME : - Le nom de votre site ; - -OUTPUT_PATH : - Le répertoire de sortie du blog. - -Quand je dis qu’on va faire simple, on fait simple ! -Passons donc à ce quoi doit ressembler le fichier de configuration :: - - # -*- coding: utf-8 -*- - AUTHOR = "Guillaume" - DEFAULT_CATEGORY = "GNU-Linux" - SITENAME = "Free Culture" - - -Si vous avez un serveur comme Apache de configuré pour votre machine, vous -pouvez paramétrer le répertoire de sortie vers **/var/www/blog** par exemple :: - - OUTPUT_PATH = "/var/www/blog" - -Une remarque importante. Si vous avez besoin de passer un caractère accentué, il -faut le préciser que la chaine est en unicode en faisant par exemple -*AUTHOR = u"Guillaume LAMÉ"* - -Pour bien vérifier que les paramètres sont bien pris en compte, nous allons enlever les lignes *:author: Guillaume* et *:category: GNU-Linux* de notre fichier -**premier_article.rst** et regénérer le blog. - -Rafraichissez votre page, ce devrait être bon. - -Nous allons maintenant passer en revue les différents paramètres de Pelican. Je les -ai regroupé par thème. Cependant, c’est surtout un listing avant de rentrer dans les -détails au prochain chapitre. - -Flux de syndication -=================== - -CATEGORY_FEED_ATOM : - Chemin d’écriture des flux Atom liés aux catégories ; - -CATEGORY_FEED_RSS : - Idem pour les flux rss (Optionnel); - -FEED_ATOM : - Chemin du flux Atom global ; - -FEED_RSS : - Chemin du flux Rss global (Optionnel); - -TAG_FEED_ATOM : - Chemin des flux Atom pour les tags (Optionnel); - -TAG_FEED_RSS : - Chemin des flux Rss pour les tags (Optionnel). - - -Traductions -=========== - -DEFAULT_LANG : - Le langage par défaut à utiliser. «*en*» par défaut ; - -TRANSLATION_FEED : - Chemin du flux pour les traductions. - - -Thèmes -====== - -CSS_FILE : - Fichier css à utiliser si celui-ci est différent du fichier par défaut (*main.css*) ; - -DISPLAY_PAGES_ON_MENU : - Affiche ou non les pages statiques sur le menu du thème ; - -DISQUS_SITENAME : - Indiquer le nom du site spécifié sur Disqus ; - -GITHUB_URL : - Indiquez votre url Github ; - -GOOGLE_ANALYTICS : - 'UA-XXXX-YYYY' pour activer Google analytics ; - -GOSQUARED_SITENAME : - 'XXX-YYYYYY-X' pour activer GoSquared ; - -JINJA_EXTENSIONS : - Liste d'extension Jinja2 que vous souhaitez utiliser ; - -LINKS : - Une liste de tuples (Titre, url) pour afficher la liste de lien ; - -PDF_PROCESSOR : - Génère ou non les articles et pages au format pdf ; - -NEWEST_FIRST_ARCHIVES : - Met les articles plus récent en tête de l'archive ; - -SOCIAL : - Une liste de tuples (Titre, url) pour afficher la liste de lien dans la section "Social" ; - -STATIC_THEME_PATHS : - Répertoire du thème que vous souhaitez importer dans l'arborescence finale ; - -THEME : - Thème à utiliser: - -TWITTER_USERNAME : - Permet d'afficher un bouton permettant le tweet des articles. - -Pelican est fournit avec :doc:`pelican-themes`, un script permettant de gérer les thèmes - - - -Paramètres divers -================= - -DEFAULT_DATE: - Date par défaut à utiliser si l'information de date n'est pas spécifiée - dans les metadonnées de l'article. - Si 'fs', Pelican se basera sur le *mtime* du fichier. - Si c'est un tuple, il sera passé au constructeur datetime.datetime pour - générer l'objet datetime utilisé par défaut. - -KEEP_OUTPUT DIRECTORY : - Ne génère que les fichiers modifiés et n'efface pas le repertoire de sortie ; - -MARKUP : - Langage de balisage à utiliser ; - -PATH : - Répertoire à suivre pour les fichiers inclus ; - -SITEURL : - URL de base de votre site ; - -STATIC_PATHS : - Les chemins statiques que vous voulez avoir accès sur le chemin de sortie "statique" ; - -MARKDOWN_EXTENSIONS : - Liste des extentions Markdown que vous souhaitez utiliser ; diff --git a/docs/fr/conventions.rst b/docs/fr/conventions.rst deleted file mode 100644 index bf88c07e..00000000 --- a/docs/fr/conventions.rst +++ /dev/null @@ -1,18 +0,0 @@ -Conventions -########### - -Environnement de test -===================== - -Les exemples sont basées sur une distribution Debian. Pour les autres distributions, -il y aura des ajustements à faire, notamment pour l’installation de Pelican. Les -noms des paquets peuvent changer. - -Conventions typographiques -========================== - -Un petit rappel concernant les codes sources. - - * $ correspond à une ligne à exécuter en tant qu’utilisateur courant du systême ; - * # correspond à une ligne à exécuter en tant que root ; - * **settings.py** : Les noms des répertoires et fichiers sont en gras. diff --git a/docs/fr/faq.rst b/docs/fr/faq.rst deleted file mode 100644 index d945f447..00000000 --- a/docs/fr/faq.rst +++ /dev/null @@ -1,40 +0,0 @@ -Foire aux questions (FAQ) -######################### - -Voici un résumé des questions fréquemment posées pour pelican. - -Est-il obligatoire d'avoir un fichier de configuration ? -======================================================== - -Non. Les fichiers de configuration sont juste un moyen facile de configurer -pelican. Pour les opérations de base, il est possible de spécifier des -options -en invoquant pelican avec la ligne de commande (voir pelican --help pour -plus -d'informations à ce sujet) - -Je crée mon propre thème, comment utiliser pygments? -==================================================== - -Pygment ajoute quelques classes au contenu généré, de sorte qua colorisation -de votre thème se fait grâce à un fichier css. Vous pouvez jeter un oeil à -celui proposé par`sur le site du projet `_ - -Comment puis-je créer mon propre thèm -===================================== - -Vueillez vous référer à :ref:`theming-pelican-fr`. - -Comment puis-je aider? -====================== - -Vous avez plusieurs options pour aider. Tout d'abord, vous pouvez utiliser -le -pélican, et signaler toute idée ou problème que vous avez sur le bugtracker -. - -Si vous voulez contribuer, jeter un oeil au dépôt git , ajoutez vos -modifications et faites une demande, je les regarderai dès que possible - -Vous pouvez aussi contribuer en créant des thèmes, et/ou compléter la -documentation. diff --git a/docs/fr/index.rst b/docs/fr/index.rst deleted file mode 100644 index 2deb5050..00000000 --- a/docs/fr/index.rst +++ /dev/null @@ -1,57 +0,0 @@ -Pelican -####### - -Pelican est un generateur de blog simple codé en python - -* Écrivez vos articles directement dans votre éditeur favori (vim !) et - directement en syntaxe reStructuredText ou Markdown ; -* Un outil simple en ligne de conmmande pour (re)générer le blog ; -* Sortie complètement statique, facile pour l'héberger n'importe où ; - -Fonctionnalités -=============== - -Pelican supporte actuellement : - -* des articles de blog ; -* des pages statiques ; -* les commentaires via un service externe (`disqus `_) - Notez qu'étant bien un service externe assez pratique, vous ne gérez pas - vous même les commentaires. Ce qui pourrait occasionner une perte de vos données; -* support de template (les templates sont crées avec `jinja2 `_) ; -* génération optionnelle de vos pages et articles en pdf. - -Pourquoi le nom "Pelican" ? -============================ - -Vous n'avez pas remarqué ? "Pelican" est un anagramme pour "Calepin" ;) - -Code source -=========== - -Vous pouvez accéder au code source via git à l'adresse -http://github.com/getpelican/pelican/ - -Feedback ! -========== - -Si vous voulez de nouvelles fonctionnalitées pour Pelican, n'hésitez pas à nous le dire, -à cloner le dépôt, etc … C'est open source !!! - -Contactez Alexis à "alexis at notmyidea dot org" pour quelques requêtes ou retour d'expérience que ce soi ! - -Documentation -============= - -.. toctree:: - :maxdepth: 2 - - conventions - installation - bases - configuration - themes - parametres_article - astuces - faq - pelican-themes diff --git a/docs/fr/installation.rst b/docs/fr/installation.rst deleted file mode 100644 index da327725..00000000 --- a/docs/fr/installation.rst +++ /dev/null @@ -1,67 +0,0 @@ -Installation et mise à jour de Pelican -###################################### - -Installation -============ - -Il y a deux façons d’installer Pelican sur son système. La première est via l’utilitaire -pip, l’autre façon est de télécharger Pelican via Github. Ici nous allons voir les deux -façons de procéder. - -Via pip -------- - -Pour installer Pelican via pip, vous aurez besoin du paquet python-pip. puis installez Pelican :: - - # apt-get install python-pip - # pip install pelican - - -Via Github ----------- - -Pour installer Pelican en reprenant le code via Github, nous aurons besoin du paquet -git-core pour récupérez les sources de Pelican. Puis nous procédons à l’installation :: - - # apt-get install git-core - $ git clone https://github.com/getpelican/pelican.git - $ cd pelican - # python setup.py install - -Mises à jour -============ - -Via pip -------- - -Rien de bien compliqué pour mettre à jour via pip :: - - $ cd votreRepertoireSource - $ pip install --upgrade pelican - - -Via Github ----------- - -C'est un peu plus long avec Github par contre :: - - $ cd votreRepertoireSource - $ git pull origin master - $ cd pelican - # python setup.py install - -Vous aurez un message d’erreur si le module setuptools de python n’est pas installé. -La manipulation est la suivante :: - - # apt-get install python-setuptools - -Alors, quelle méthode choisir ? -=============================== - -Vous avez le choix entre deux méthodes, mais aussi entre deux concepts. La méthode -de Github est la version de développement, où les modifications arrivent assez -fréquemment sans être testées à fond. La version de pip est une version arrêtée avec un -numéro de version dans laquelle vous aurez moins de bug. N’oubliez cependant pas -que le projet est très jeune et manque donc de maturité. Si vous aimez avoir les toutes -dernières versions utilisez Github, sinon penchez vous sur pip. - diff --git a/docs/fr/parametres_article.rst b/docs/fr/parametres_article.rst deleted file mode 100644 index a3d25b55..00000000 --- a/docs/fr/parametres_article.rst +++ /dev/null @@ -1,106 +0,0 @@ -Les paramètres des articles dans Pelican -######################################## - -Les catégories -============== - -Nous avons vu que pour affecter un article à une catégorie, nous avions le paramètre *:category:*. -Il y a cependant plus simple, affecter un répertoire à une catégorie. - -Dans le répertoire ou vous avez vos articles, créez le repertoire **GNU-Linux** et déplacez y le fichier -**premier_article.rst**. Bien évidemment nous ne verront pas la différence, car jusqu'ici *GNU-Linux* -est notre catégorie par défaut. - -Nous allons faire un autre exemple d'article avec la catégorie Pelican. Créez le répertoire **Pelican** -et collez cette exemple d'article :: - - Préparation de la documentation - ############################### - - :date: 2011-01-27 15:28 - :tags: documentation - - Il y a quand même pas mal de boulot pour faire une documentation ! - -Et lancez la compilation du blog. Vous voyez que la catégorie est affectée automatiquement. - -Les tags -======== - -Pour les tags, il n'y a rien de compliqué. il suffit de mettre le(s) tags séparés si besoin d'une virgule. :: - - Préparation de la documentation - ############################### - - :date: 2011-01-27 15:28 - :tags: documentation, pelican - -Par contre, par soucis de clarté au niveau des url je vous conseille de mettre les expression de plusieurs -mots séparées par des tirets :: - - :tags: mise-a-jour - -et non :: - - :tags: mise a jour - - -Les auteurs -=========== - -Par défaut, vous pouvez indiqué votre nom en tant qu'auteur dans le fichier de configuration. -S'il y a plusieurs auteurs pour le site, vous pouvez le définir manuellement dans -l'article avec la méta-donnée :: - - :author: Guillaume - -La date -======= - -La date se met au format anglophone : **YYYY-MM-DD hh:mm** :: - - :date: 2011-01-31 14:12 - - -Les traductions -=============== - -Pelican permet de générer un blog multilingue assez facilement. Pour cela nous devons : - -* Définir la langue de base du blog ; -* Donner une référence à l'article initial ; -* Définir la langue du fichier traduit et y reporter la référence. - -Pour définir la langue de base nous allons modifier le fichier **settings.py** et y rajouter la ligne suivante :: - - DEFAULT_LANG = "fr" - -Puis ajouter la référence dans notre article d'origine qui deviendra :: - - Préparation de la documentation - ############################### - - :date: 2011-01-27 15:28 - :tags: documentation - :slug: preparation-de-la-documentation - - Il y a quand même pas mal de boulot pour faire une documentation ! - -Nous n'avons plus qu'à créer l'article en anglais :: - - Start of documentation - ###################### - - :slug: preparation-de-la-documention - :lang: en - - There are still a lot of work to documentation ! - -**Il est important de comprendre que la valeur de :slug: deviendra votre url. Ne mettez donc pas un diminutif pour -identifier l'article** - -Rien de plus à savoir pour traduire efficacement des articles. - - -Maintenant que vous avez toutes les clés en main pour créer un article, nous allons passer à la personnalisation -du fichier de configuration. diff --git a/docs/fr/pelican-themes.rst b/docs/fr/pelican-themes.rst deleted file mode 100644 index 810fa785..00000000 --- a/docs/fr/pelican-themes.rst +++ /dev/null @@ -1,172 +0,0 @@ -pelican-themes -############## - - - -Description -=========== - -``pelican-themes`` est un outil en lignes de commandes pour gérer les thèmes de Pelican. - - -Utilisation: -"""""""""""" - -| pelican-themes [-h] [-l] [-i *chemin d'un thème* [*chemin d'un thème* ...]] -| [-r *nom d'un thème* [*nom d'un thème* ...]] -| [-s *chemin d'un thème* [*chemin d'un thème* ...]] [-v] [--version] - -Arguments: -"""""""""" - - --h, --help Afficher l'aide et quitter - --l, --list Montrer les thèmes installés - --i chemin, --install chemin Chemin(s) d'accès d'un ou plusieurs thème à installer - --r nom, --remove nom Noms d'un ou plusieurs thèmes à installer - --s chemin, --symlink chemin Fonctionne de la même façon que l'option ``--install``, mais crée un lien symbolique au lieu d'effectuer une copie du thème vers le répertoire des thèmes. - Utile pour le développement de thèmes. - --v, --verbose Sortie détaillée - ---version Affiche la version du script et quitte - - - -Exemples -======== - - -Lister les thèmes installés -""""""""""""""""""""""""""" - -``pelican-themes`` peut afficher les thèmes disponibles. - -Pour cela, vous pouvez utiliser l'option ``-l`` ou ``--list``, comme ceci: - -.. code-block:: console - - $ pelican-themes -l - notmyidea - two-column@ - simple - $ pelican-themes --list - notmyidea - two-column@ - simple - -Dans cet exemple, nous voyons qu'il y a trois thèmes d'installés: ``notmyidea``, ``simple`` and ``two-column``. - -``two-column`` est suivi d'un ``@`` par ce que c'est un lien symbolique (voir `Créer des liens symboliques`_). - -Notez que vous pouvez combiner l'option ``--list`` avec l'option ``--verbose``, pour afficher plus de détails: - -.. code-block:: console - - $ pelican-themes -v -l - /usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/notmyidea - /usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/two-column (symbolic link to `/home/skami/Dev/Python/pelican-themes/two-column') - /usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/simple - - -Installer des thèmes -"""""""""""""""""""" - -Vous pouvez installer un ou plusieurs thèmes en utilisant l'option ``-i`` ou ``--install``. - -Cette option prends en argument le(s) chemin(s) d'accès du ou des thème(s) que vous voulez installer, et peut se combiner avec l'option ``--verbose``: - -.. code-block:: console - - # pelican-themes --install ~/Dev/Python/pelican-themes/notmyidea-cms --verbose - -.. code-block:: console - - # pelican-themes --install ~/Dev/Python/pelican-themes/notmyidea-cms\ - ~/Dev/Python/pelican-themes/martyalchin \ - --verbose - -.. code-block:: console - - # pelican-themes -vi ~/Dev/Python/pelican-themes/two-column - - -Supprimer des thèmes -"""""""""""""""""""" - -``pelican-themes`` peut aussi supprimer des thèmes précédemment installés grâce à l'option ``-r`` ou ``--remove``. - -Cette option prends en argument le ou les nom(s) des thèmes que vous voulez installer, et peux se combiner avec l'option ``--verbose``: - -.. code-block:: console - - # pelican-themes --remove two-column - -.. code-block:: console - - # pelican-themes -r martyachin notmyidea-cmd -v - - - - - -Créer des liens symboliques -""""""""""""""""""""""""""" - - -L'option ``-s`` ou ``--symlink`` de ``pelican-themes`` permet de lier symboliquement un thème. - -Cette option s'utilise exactement comme l'option ``--install``: - -.. code-block:: console - - # pelican-themes --symlink ~/Dev/Python/pelican-themes/two-column - -Dans l'exemple ci dessus, un lien symbolique pointant vers le thème ``two-column`` a été installé dans le répertoire des thèmes de Pelican, toute modification sur le thème ``two-column`` prendra donc effet immédiatement. - -Cela peut être pratique pour le développement de thèmes - -.. code-block:: console - - $ sudo pelican-themes -s ~/Dev/Python/pelican-themes/two-column - $ pelican ~/Blog/content -o /tmp/out -t two-column - $ firefox /tmp/out/index.html - $ vim ~/Dev/Pelican/pelican-themes/two-coumn/static/css/main.css - $ pelican ~/Blog/content -o /tmp/out -t two-column - $ cp /tmp/bg.png ~/Dev/Pelican/pelican-themes/two-coumn/static/img/bg.png - $ pelican ~/Blog/content -o /tmp/out -t two-column - $ vim ~/Dev/Pelican/pelican-themes/two-coumn/templates/index.html - $ pelican ~/Blog/content -o /tmp/out -t two-column - - -Notez que cette fonctionnalité nécessite d'avoir un système d'exploitation et un système de fichiers supportant les liens symboliques, elle n'est donc pas disponible sous Micro$oft®©™ Fenêtre®©™. - -Faire plusieurs choses à la fois -"""""""""""""""""""""""""""""""" - - -Les options ``--install``, ``--remove`` et ``--symlink`` peuvent être employées en même temps, ce qui permets de réaliser plusieurs opérations en même temps: - -.. code-block:: console - - # pelican-themes --remove notmyidea-cms two-column \ - --install ~/Dev/Python/pelican-themes/notmyidea-cms-fr \ - --symlink ~/Dev/Python/pelican-themes/two-column \ - --verbose - -Dans cette exemple, le thème ``notmyidea-cms`` sera remplacé par le thème ``notmyidea-cms-fr`` et le thème ``two-column`` sera lié symboliquement... - - - -À voir également -================ - -- http://docs.notmyidea.org/alexis/pelican/ -- ``/usr/share/doc/pelican/`` si vous avez installé Pelican par le `dépôt APT `_ - - - diff --git a/docs/fr/themes.rst b/docs/fr/themes.rst deleted file mode 100644 index 20d9d41f..00000000 --- a/docs/fr/themes.rst +++ /dev/null @@ -1,171 +0,0 @@ -.. _theming-pelican: - -Cette page est une traduction de la documentation originale, en anglais et -disponible `ici <../themes.html>`_. - -Comment créer des thèmes pour Pelican -##################################### - -Pelican utlise le très bon moteur de template `jinja2 `_ -pour produire de l'HTML. La syntaxe de jinja2 est vraiment très simple. Si vous -voulez créer votre propre thème, soyez libre de prendre inspiration sur le theme -"simple" qui est disponible `ici -`_ - -Structure -========= - -Pour réaliser votre propre thème vous devez respecter la structure suivante :: - - ├── static - │   ├── css - │   └── images - └── templates - ├── archives.html // pour afficher les archives - ├── article.html // généré pour chaque article - ├── categories.html // doit lister toutes les catégories - ├── category.html // généré pour chaque catégorie - ├── index.html // la page d'index, affiche tous les articles - ├── page.html // généré pour chaque page - ├── tag.html // généré pour chaque tag - └── tags.html // doit lister tous les tags. Peut être un nuage de tag. - - -* `static` contient tout le contenu statique. Il sera copié dans le dossier - `theme/static`. J'ai mis un dossier css et un image, mais ce sont juste des - exemples. Mettez ce dont vous avez besoin ici. - -* `templates` contient tous les templates qui vont être utiliser pour générer les - pages. J'ai juste mis les templates obligatoires ici, vous pouvez définir les - vôtres si cela vous aide à vous organiser pendant que vous réaliser le thème. - Vous pouvez par exemple utiliser les directives {% include %} et {% extends %} - de jinja2. - -Templates et variables -====================== - -Cela utilise une syntaxe simple, que vous pouvez insérer dans vos pages HTML. -Ce document décrit les templates qui doivent exister dans un thème, et quelles -variables seront passées à chaque template, au moment de le générer. - -Tous les templates recevront les variables définies dans votre fichier de -configuration, si elles sont en capitales. Vous pouvez y accéder directement. - -Variables communes ------------------- - -Toutes ces variables seront passées à chaque template. - -============= =================================================== -Variable Description -============= =================================================== -articles C'est la liste des articles, ordonnée décroissante - par date. Tous les éléments de la liste sont des - objets `Article`, vous pouvez donc accéder à leurs - propriétés (exemple : title, summary, author, etc). -dates La même liste d'articles, ordonnée croissante par - date. -tags Un dictionnaire contenant tous les tags (clés), et - la liste des articles correspondants à chacun - d'entre eux (valeur). -categories Un dictionnaire contenant toutes les catégories - (clés), et la liste des articles correspondants à - chacune d'entre elles (valeur). -pages La liste des pages. -============= =================================================== - -index.html ----------- - -La page d'accueil de votre blog, sera générée dans output/index.html. - -Si la pagination est activée, les pages suivantes seront à l'adresse -output/index`n`.html. - -=================== =================================================== -Variable Description -=================== =================================================== -articles_paginator Un objet paginator de la liste d'articles. -articles_page La page actuelle d'articles. -dates_paginator Un objet paginator de la liste d'articles, ordonné - par date croissante. -dates_pages La page actuelle d'articles, ordonnée par date - croissante. -page_name 'index'. -=================== =================================================== - -category.html -------------- - -Ce template sera généré pour chaque catégorie existante, et se retrouvera -finalement à output/category/`nom de la catégorie`.html. - -Si la pagination est activée, les pages suivantes seront disponibles à -l'adresse output/category/`nom de la catégorie``n`.html. - -=================== =================================================== -Variable Description -=================== =================================================== -category La catégorie qui est en train d'être générée. -articles Les articles dans cette catégorie. -dates Les articles dans cette catégorie, ordonnés par - date croissante. -articles_paginator Un objet paginator de la liste d'articles. -articles_page La page actuelle d'articles. -dates_paginator Un objet paginator de la liste d'articles, ordonné - par date croissante. -dates_pages La page actuelle d'articles, ordonnée par date - croissante. -page_name 'category/`nom de la catégorie`'. -=================== =================================================== - -article.html -------------- - -Ce template sera généré pour chaque article. Les fichiers .html seront -disponibles à output/`nom de l'article`.html. - -============= =================================================== -Variable Description -============= =================================================== -article L'objet article à afficher. -category Le nom de la catégorie de l'article actuel. -============= =================================================== - -page.html ---------- - -Pour chaque page ce template sera généré à l'adresse -output/`nom de la page`.html - -============= =================================================== -Variable Description -============= =================================================== -page L'objet page à afficher. Vous pouvez accéder à son - titre (title), slug, et son contenu (content). -============= =================================================== - -tag.html --------- - -Ce template sera généré pour chaque tag. Cela créera des fichiers .html à -l'adresse output/tag/`nom du tag`.html. - -Si la pagination est activée, les pages suivantes seront disponibles à -l'adresse output/tag/`nom du tag``n`.html - -=================== =================================================== -Variable Description -=================== =================================================== -tag Nom du tag à afficher. -articles Une liste des articles contenant ce tag. -dates Une liste des articles contenant ce tag, ordonnée - par date croissante. -articles_paginator Un objet paginator de la liste d'articles. -articles_page La page actuelle d'articles. -dates_paginator Un objet paginator de la liste d'articles, ordonné - par date croissante. -dates_pages La page actuelle d'articles, ordonnée par date - croissante. -page_name 'tag/`nom du tag`'. -=================== =================================================== diff --git a/docs/getting_started.rst b/docs/getting_started.rst deleted file mode 100644 index 85a1b559..00000000 --- a/docs/getting_started.rst +++ /dev/null @@ -1,313 +0,0 @@ -Getting started -############### - -Installing Pelican -================== - -You're ready? Let's go! You can install Pelican via several different methods. -The simplest is via `pip `_:: - - $ pip install pelican - -If you don't have ``pip`` installed, an alternative method is ``easy_install``:: - - $ easy_install pelican - -While the above is the simplest method, the recommended approach is to create -a virtual environment for Pelican via virtualenv_ and virtualenvwrapper_ before -installing Pelican. Assuming you've followed the virtualenvwrapper -`installation `_ -and `shell configuration -`_ -steps, you can then open a new terminal session and create a new virtual -environment for Pelican:: - - $ mkvirtualenv pelican - -Once the virtual environment has been created and activated, Pelican can be -be installed via ``pip`` or ``easy_install`` as noted above. Alternatively, if -you have the project source, you can install Pelican using the distutils -method:: - - $ cd path-to-Pelican-source - $ python setup.py install - -If you have Git installed and prefer to install the latest bleeding-edge -version of Pelican rather than a stable release, use the following command:: - - $ pip install -e git://github.com/getpelican/pelican#egg=pelican - -If you plan on using Markdown as a markup format, you'll need to install the -Markdown library as well:: - - $ pip install Markdown - -Upgrading ---------- - -If you installed a stable Pelican release via ``pip`` or ``easy_install`` and -wish to upgrade to the latest stable release, you can do so by adding -``--upgrade`` to the relevant command. For pip, that would be:: - - $ pip install --upgrade pelican - -If you installed Pelican via distutils or the bleeding-edge method, simply -perform the same step to install the most recent version. - -Dependencies ------------- - -At this time, Pelican is dependent on the following Python packages: - -* feedgenerator, to generate the Atom feeds -* jinja2, for templating support -* docutils, for supporting reStructuredText as an input format - -If you're not using Python 2.7, you will also need the ``argparse`` package. - -Optionally: - -* pygments, for syntax highlighting -* Markdown, for supporting Markdown as an input format -* Typogrify, for typographical enhancements - -Kickstart a blog -================ - -Following is a brief tutorial for those who want to get started right away. -We're going to assume that virtualenv_ and virtualenvwrapper_ are installed and -configured; if you've installed Pelican outside of a virtual environment, -you can skip to the ``pelican-quickstart`` command. Let's first create a new -virtual environment and install Pelican into it:: - - $ mkvirtualenv pelican - $ pip install pelican Markdown - -Next we'll create a directory to house our site content and configuration files, -which can be located any place you prefer, and associate this new project with -the currently-active virtual environment:: - - $ mkdir ~/code/yoursitename - $ cd ~/code/yoursitename - $ setvirtualenvproject - -Now we can run the ``pelican-quickstart`` command, which will ask some questions -about your site:: - - $ pelican-quickstart - -Once you finish answering all the questions, you can begin adding content to the -*content* folder that has been created for you. (See *Writing articles using -Pelican* section below for more information about how to format your content.) -Once you have some content to generate, you can convert it to HTML via the -following command:: - - $ make html - -If you'd prefer to have Pelican automatically regenerate your site every time a -change is detected (handy when testing locally), use the following command -instead:: - - $ make regenerate - -To serve the site so it can be previewed in your browser at -http://localhost:8000:: - - $ make serve - -Normally you would need to run ``make regenerate`` and ``make serve`` in two -separate terminal sessions, but you can run both at once via:: - - $ make devserver - -The above command will simultaneously run Pelican in regeneration mode as well -as serve the output at http://localhost:8000. Once you are done testing your -changes, you should stop the development server via:: - - $ ./develop_server.sh stop - -When you're ready to publish your site, you can upload it via the method(s) you -chose during the ``pelican-quickstart`` questionnaire. For this example, we'll -use rsync over ssh:: - - $ make rsync_upload - -That's it! Your site should now be live. - -Writing articles using Pelican -============================== - -File metadata --------------- - -Pelican tries to be smart enough to get the information it needs from the -file system (for instance, about the category of your articles), but some -information you need to provide in the form of metadata inside your files. - -You can provide this metadata in reStructuredText text files via the -following syntax (give your file the ``.rst`` extension):: - - My super title - ############## - - :date: 2010-10-03 10:20 - :tags: thats, awesome - :category: yeah - :author: Alexis Metaireau - -Pelican implements an extension of reStructuredText to enable support for the -``abbr`` HTML tag. To use it, write something like this in your post:: - - This will be turned into :abbr:`HTML (HyperText Markup Language)`. - -You can also use Markdown syntax (with a file ending in ``.md``). -Markdown generation will not work until you explicitly install the ``Markdown`` -package, which can be done via ``pip install Markdown``. Metadata syntax for -Markdown posts should follow this pattern:: - - Date: 2010-12-03 - Title: My super title - Tags: thats, awesome - Slug: my-super-post - - This is the content of my super blog post. - -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``. - -Generate your blog ------------------- - -The ``make`` shortcut commands mentioned in the ``Kickstart a blog`` section -are mostly wrappers around the ``pelican`` command that generates the HTML from -the content. The ``pelican`` command can also be run directly:: - - $ pelican /path/to/your/content/ [-s path/to/your/settings.py] - -The above command will generate your weblog and save it in the ``output/`` -folder, using the default theme to produce a simple site. The default theme is -simple HTML without styling and is provided so folks may use it as a basis for -creating their own themes. - -Pelican has other command-line switches available. Have a look at the help to -see all the options you can use:: - - $ pelican --help - -Auto-reload ------------ - -It's possible to tell Pelican to watch for your modifications, instead of -manually re-running it every time you want to see your changes. To enable this, -run the ``pelican`` command with the ``-r`` or ``--autoreload`` option. - -Pages ------ - -If you create a folder named ``pages``, all the files in it will be used to -generate static pages. - -Then, use the ``DISPLAY_PAGES_ON_MENU`` setting, which will add all the pages to -the menu. - -If you want to exclude any pages from being linked to or listed in the menu -then add a ``status: hidden`` attribute to its metadata. This is useful for -things like making error pages that fit the generated theme of your site. - -Importing an existing blog --------------------------- - -It is possible to import your blog from Dotclear, WordPress, and RSS feeds using -a simple script. See :ref:`import`. - -Translations ------------- - -It is possible to translate articles. To do so, you need to add a ``lang`` meta -attribute to your articles/pages and set a ``DEFAULT_LANG`` setting (which is -English [en] by default). With those settings in place, only articles with the -default language will be listed, and each article will be accompanied by a list -of available translations for that article. - -Pelican uses the article's URL "slug" to determine if two or more articles are -translations of one another. The slug can be set manually in the file's -metadata; if not set explicitly, Pelican will auto-generate the slug from the -title of the article. - -Here is an example of two articles, one in English and the other in French. - -The English article:: - - Foobar is not dead - ################## - - :slug: foobar-is-not-dead - :lang: en - - That's true, foobar is still alive! - -And the French version:: - - Foobar n'est pas mort ! - ####################### - - :slug: foobar-is-not-dead - :lang: fr - - Oui oui, foobar est toujours vivant ! - -Post content quality notwithstanding, you can see that only item in common -between the two articles is the slug, which is functioning here as an -identifier. If you'd rather not explicitly define the slug this way, you must -then instead ensure that the translated article titles are identical, since the -slug will be auto-generated from the article title. - -Syntax highlighting ---------------------- - -Pelican is able to provide colorized syntax highlighting for your code blocks. -To do so, you have to use the following conventions (you need to put this in -your content files). - -For RestructuredText, use the code-block directive:: - - .. code-block:: identifier - - - -For Markdown, include the language identifier just above the code block, -indenting both the identifier and code:: - - :::identifier - - -The specified identifier (e.g. ``python``, ``ruby``) should be one that -appears on the `list of available lexers `_. - -Publishing drafts ------------------ - -If you want to publish an article as a draft (for friends to review before -publishing, for example), you can add a ``status: draft`` attribute to its -metadata. That article will then be output to the ``drafts`` folder and not -listed on the index page nor on any category page. - -Viewing the generated files ---------------------------- - -The files generated by Pelican are static files, so you don't actually need -anything special to see what's happening with the generated files. - -You can either use your browser to open the files on your disk:: - - $ firefox output/index.html - -Or run a simple web server using Python:: - - cd output && python -m SimpleHTTPServer - -.. _virtualenv: http://www.virtualenv.org/ -.. _virtualenvwrapper: http://www.doughellmann.com/projects/virtualenvwrapper/ diff --git a/docs/importer.rst b/docs/importer.rst index ba96d9c2..aa3fa935 100644 --- a/docs/importer.rst +++ b/docs/importer.rst @@ -1,74 +1,115 @@ .. _import: -================================= - Import from other blog software -================================= +Importing an existing site +########################## Description =========== -``pelican-import`` is a command line tool for converting articles from other -software to ReStructuredText. The supported formats are: +``pelican-import`` is a command-line tool for converting articles from other +software to reStructuredText or Markdown. The supported import formats are: - WordPress XML export - Dotclear export +- Posterous API +- Tumblr API - RSS/Atom feed -The conversion from HTML to reStructuredText relies on `pandoc -`_. For Dotclear, if the source posts are -written with Markdown syntax, they will not be converted (as Pelican also -supports Markdown). +The conversion from HTML to reStructuredText or Markdown relies on `Pandoc`_. +For Dotclear, if the source posts are written with Markdown syntax, they will +not be converted (as Pelican also supports Markdown). + Dependencies -"""""""""""" +============ -``pelican-import`` has two dependencies not required by the rest of pelican: +``pelican-import`` has some dependencies not required by the rest of Pelican: -- BeautifulSoup -- pandoc +- *BeautifulSoup4* and *lxml*, for WordPress and Dotclear import. Can be installed like + any other Python package (``pip install BeautifulSoup4 lxml``). +- *Feedparser*, for feed import (``pip install feedparser``). +- *Pandoc*, see the `Pandoc site`_ for installation instructions on your + operating system. -BeatifulSoup can be installed like any other Python package:: - - $ pip install BeautifulSoup - -For pandoc, install a package for your operating system from the -`pandoc site `_. +.. _Pandoc: http://johnmacfarlane.net/pandoc/ +.. _Pandoc site: http://johnmacfarlane.net/pandoc/installing.html Usage -""""" +===== -| pelican-import [-h] [--wpfile] [--dotclear] [--feed] [-o OUTPUT] -| [-m MARKUP][--dir-cat] -| input +:: + + pelican-import [-h] [--wpfile] [--dotclear] [--posterous] [--tumblr] [--feed] [-o OUTPUT] + [-m MARKUP] [--dir-cat] [--dir-page] [--strip-raw] [--disable-slugs] + [-e EMAIL] [-p PASSWORD] [-b BLOGNAME] + input|api_token|api_key + +Positional arguments +-------------------- + ============= ============================================================================ + ``input`` The input file to read + ``api_token`` (Posterous only) api_token can be obtained from http://posterous.com/api/ + ``api_key`` (Tumblr only) api_key can be obtained from http://www.tumblr.com/oauth/apps + ============= ============================================================================ Optional arguments -"""""""""""""""""" +------------------ - -h, --help show this help message and exit - --wpfile Wordpress XML export - --dotclear Dotclear export - --feed Feed to parse + -h, --help Show this help message and exit + --wpfile WordPress XML export (default: False) + --dotclear Dotclear export (default: False) + --posterous Posterous API (default: False) + --tumblr Tumblr API (default: False) + --feed Feed to parse (default: False) -o OUTPUT, --output OUTPUT - Output path - -m MARKUP Output markup + Output path (default: output) + -m MARKUP, --markup MARKUP + Output markup format (supports rst & markdown) + (default: rst) --dir-cat Put files in directories with categories name + (default: False) + --dir-page Put files recognised as pages in "pages/" sub- + directory (wordpress import only) (default: False) + --filter-author Import only post from the specified author. + --strip-raw Strip raw HTML code that can't be converted to markup + such as flash embeds or iframes (wordpress import + only) (default: False) + --disable-slugs Disable storing slugs from imported posts within + output. With this disabled, your Pelican URLs may not + be consistent with your original posts. (default: + False) + -e EMAIL, --email=EMAIL + Email used to authenticate Posterous API + -p PASSWORD, --password=PASSWORD + Password used to authenticate Posterous API + -b BLOGNAME, --blogname=BLOGNAME + Blog name used in Tumblr API + Examples ======== -for WordPress:: +For WordPress:: $ pelican-import --wpfile -o ~/output ~/posts.xml -for Dotclear:: +For Dotclear:: $ pelican-import --dotclear -o ~/output ~/backup.txt +for Posterous:: + + $ pelican-import --posterous -o ~/output --email= --password= + +For Tumblr:: + + $ pelican-import --tumblr -o ~/output --blogname= + Tests ===== To test the module, one can use sample files: -- for Wordpress: http://wpcandy.com/made/the-sample-post-collection +- for WordPress: http://wpcandy.com/made/the-sample-post-collection - for Dotclear: http://themes.dotaddict.org/files/public/downloads/lorem-backup.txt diff --git a/docs/index.rst b/docs/index.rst index 3fc1cf9f..ccfb9982 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,31 +1,41 @@ -Pelican -======= +Pelican |release| +================= -Pelican is a static site generator, written in Python_. -* Write your weblog entries directly with your editor of choice (vim!) - in reStructuredText_ or Markdown_ -* Includes a simple CLI tool to (re)generate the weblog -* Easy to interface with DVCSes and web hooks +.. ifconfig:: release.endswith('.dev') + + .. warning:: + + This documentation is for the version of Pelican currently under development. + Were you looking for version |last_stable| documentation? + + +Pelican is a static site generator, written in Python_. Highlights include: + +* Write your content directly with your editor of choice + in reStructuredText_ or Markdown_ formats +* Includes a simple CLI tool to (re)generate your site +* Easy to interface with distributed version control systems and web hooks * Completely static output is easy to host anywhere +Ready to get started? Check out the :doc:`Quickstart` guide. + Features -------- -Pelican currently supports: +Pelican |version| currently supports: -* Blog articles and pages -* Comments, via an external service (Disqus). (Please note that while - useful, Disqus is an external service, and thus the comment data will be - somewhat outside of your control and potentially subject to data loss.) +* Articles (e.g., blog posts) and pages (e.g., "About", "Projects", "Contact") +* Comments, via an external service (Disqus). If you prefer to have more + control over your comment data, self-hosted comments are another option. + Check out the `Pelican Plugins`_ repository for more details. * Theming support (themes are created using Jinja2_ templates) -* PDF generation of the articles/pages (optional) * Publication of articles in multiple languages * Atom/RSS feeds * Code syntax highlighting -* Compilation of `LESS CSS`_ (optional) * Import from WordPress, Dotclear, or RSS feeds * Integration with external tools: Twitter, Google Analytics, etc. (optional) +* Fast rebuild times thanks to content caching and selective output writing Why the name "Pelican"? ----------------------- @@ -37,35 +47,30 @@ Source code You can access the source code at: https://github.com/getpelican/pelican -Feedback / Contact us ---------------------- +How to get help, contribute, or provide feedback +------------------------------------------------ -If you want to see new features in Pelican, don't hesitate to offer suggestions, -clone the repository, etc. There are many ways to :doc:`contribute`. -That's open source, dude! - -Send a message to "authors at getpelican dot com" with any requests/feedback! You -can also join the team at `#pelican on Freenode`_ (or if you don't have an IRC -client handy, use the webchat_ for quick feedback. +See our :doc:`feedback and contribution submission guidelines `. Documentation ------------- -A French version of the documentation is available at :doc:`fr/index`. - .. toctree:: :maxdepth: 2 - getting_started + quickstart + install + content + publish settings themes plugins - internals pelican-themes importer faq tips contribute + internals report changelog @@ -75,8 +80,6 @@ A French version of the documentation is available at :doc:`fr/index`. .. _reStructuredText: http://docutils.sourceforge.net/rst.html .. _Markdown: http://daringfireball.net/projects/markdown/ .. _Jinja2: http://jinja.pocoo.org/ -.. _`LESS CSS`: http://lesscss.org/ .. _`Pelican documentation`: http://docs.getpelican.com/latest/ .. _`Pelican's internals`: http://docs.getpelican.com/en/latest/internals.html -.. _`#pelican on Freenode`: irc://irc.freenode.net/pelican -.. _webchat: http://webchat.freenode.net/?channels=pelican&uio=d4 +.. _`Pelican plugins`: https://github.com/getpelican/pelican-plugins diff --git a/docs/install.rst b/docs/install.rst new file mode 100644 index 00000000..418c8ca6 --- /dev/null +++ b/docs/install.rst @@ -0,0 +1,117 @@ +Installing Pelican +################## + +Pelican currently runs best on Python 2.7.x; earlier versions of Python are +not supported. There is provisional support for Python 3.3+, although there may +be rough edges, particularly with regards to optional 3rd-party components. + +You can install Pelican via several different methods. The simplest is via +`pip `_:: + + pip install pelican + +(Keep in mind that operating systems will often require you to prefix the above +command with ``sudo`` in order to install Pelican system-wide.) + +While the above is the simplest method, the recommended approach is to create +a virtual environment for Pelican via virtualenv_ before installing Pelican. +Assuming you have virtualenv_ installed, you can then open a new terminal +session and create a new virtual environment for Pelican:: + + virtualenv ~/virtualenvs/pelican + cd ~/virtualenvs/pelican + source bin/activate + +Once the virtual environment has been created and activated, Pelican can be +be installed via ``pip install pelican`` as noted above. Alternatively, if +you have the project source, you can install Pelican using the distutils +method:: + + cd path-to-Pelican-source + python setup.py install + +If you have Git installed and prefer to install the latest bleeding-edge +version of Pelican rather than a stable release, use the following command:: + + pip install -e "git+https://github.com/getpelican/pelican.git#egg=pelican" + +Once Pelican is installed, you can run ``pelican --help`` to see basic usage +options. For more detail, refer to the :doc:`Publish` section. + +Optional packages +----------------- + +If you plan on using `Markdown `_ as a +markup format, you'll need to install the Markdown library:: + + pip install Markdown + +Typographical enhancements can be enabled in your settings file, but first the +requisite `Typogrify `_ library must be +installed:: + + pip install typogrify + +Dependencies +------------ + +When Pelican is installed, the following dependent Python packages should be +automatically installed without any action on your part: + +* `feedgenerator `_, to generate the + Atom feeds +* `jinja2 `_, for templating support +* `pygments `_, for syntax highlighting +* `docutils `_, for supporting + reStructuredText as an input format +* `pytz `_, for timezone definitions +* `blinker `_, an object-to-object and + broadcast signaling system +* `unidecode `_, for ASCII + transliterations of Unicode text +* `six `_, for Python 2 and 3 compatibility + utilities +* `MarkupSafe `_, for a markup safe + string implementation +* `python-dateutil `_, to read + the date metadata + +Upgrading +--------- + +If you installed a stable Pelican release via ``pip`` or ``easy_install`` and +wish to upgrade to the latest stable release, you can do so by adding +``--upgrade`` to the relevant command. For pip, that would be:: + + pip install --upgrade pelican + +If you installed Pelican via distutils or the bleeding-edge method, simply +perform the same step to install the most recent version. + +Kickstart your site +=================== + +Once Pelican has been installed, you can create a skeleton project via the +``pelican-quickstart`` command, which begins by asking some questions about +your site:: + + pelican-quickstart + +Once you finish answering all the questions, your project will consist of the +following hierarchy (except for *pages* — shown in parentheses below — which you +can optionally add yourself if you plan to create non-chronological content):: + + yourproject/ + ├── content + │   └── (pages) + ├── output + ├── develop_server.sh + ├── fabfile.py + ├── Makefile + ├── pelicanconf.py # Main settings file + └── publishconf.py # Settings to use when ready to publish + +The next step is to begin to adding content to the *content* folder that has +been created for you. + +.. _virtualenv: http://www.virtualenv.org/ diff --git a/docs/internals.rst b/docs/internals.rst index a6264476..303a327f 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -12,8 +12,8 @@ original author wrote with some software design information. Overall structure ================= -What Pelican does is take a list of files and process them into some -sort of output. Usually, the input files are reStructuredText and Markdown +What Pelican does is take a list of files and process them into some sort of +output. Usually, the input files are reStructuredText and Markdown files, and the output is a blog, but both input and output can be anything you want. @@ -23,9 +23,9 @@ The logic is separated into different classes and concepts: on. Since those operations are commonly used, the object is created once and then passed to the generators. -* **Readers** are used to read from various formats (Markdown and - reStructuredText for now, but the system is extensible). Given a file, they return - metadata (author, tags, category, etc.) and content (HTML-formatted). +* **Readers** are used to read from various formats (HTML, Markdown and + reStructuredText for now, but the system is extensible). Given a file, they + return metadata (author, tags, category, etc.) and content (HTML-formatted). * **Generators** generate the different outputs. For instance, Pelican comes with ``ArticlesGenerator`` and ``PageGenerator``. Given a configuration, they can do @@ -44,22 +44,20 @@ method that returns HTML content and some metadata. Take a look at the Markdown reader:: - class MarkdownReader(Reader): + class MarkdownReader(BaseReader): enabled = bool(Markdown) - def read(self, filename): + def read(self, source_path): """Parse content and metadata of markdown files""" - text = open(filename) + text = pelican_open(source_path) md = Markdown(extensions = ['meta', 'codehilite']) content = md.convert(text) metadata = {} for name, value in md.Meta.items(): - if name in _METADATA_FIELDS: - meta = _METADATA_FIELDS[name](value[0]) - else: - meta = value[0] - metadata[name.lower()] = meta + name = name.lower() + meta = self.process_metadata(name, value[0]) + metadata[name] = meta return content, metadata Simple, isn't it? diff --git a/docs/pelican-themes.rst b/docs/pelican-themes.rst index 23be8355..7090c648 100644 --- a/docs/pelican-themes.rst +++ b/docs/pelican-themes.rst @@ -153,12 +153,3 @@ The ``--install``, ``--remove`` and ``--symlink`` option are not mutually exclus --verbose In this example, the theme ``notmyidea-cms`` is replaced by the theme ``notmyidea-cms-fr`` - - - - -See also -======== - -- http://docs.notmyidea.org/alexis/pelican/ -- ``/usr/share/doc/pelican/`` if you have installed Pelican using the `APT repository `_ diff --git a/docs/plugins.rst b/docs/plugins.rst index 00e8ba04..15fcf109 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -3,37 +3,55 @@ Plugins ####### -Since version 3.0, Pelican manages plugins. Plugins are a way to add features -to Pelican without having to directly hack Pelican code. - -Pelican is shipped with a set of core plugins, but you can easily implement -your own (and this page describes how). +Beginning with version 3.0, Pelican supports plugins. Plugins are a way to add +features to Pelican without having to directly modify the Pelican core. How to use plugins ================== -To load plugins, you have to specify them in your settings file. You have two -ways to do so. -Either by specifying strings with the path to the callables:: +To load plugins, you have to specify them in your settings file. There are two +ways to do so. The first method is to specify strings with the path to the +callables:: - PLUGINS = ['pelican.plugins.gravatar',] + PLUGINS = ['package.myplugin',] -Or by importing them and adding them to the list:: +Alternatively, another method is to import them and add them to the list:: - from pelican.plugins import gravatar - PLUGINS = [gravatar, ] + from package import myplugin + PLUGINS = [myplugin,] -If your plugins are not in an importable path, you can specify a ``PLUGIN_PATH`` -in the settings:: +.. note:: - PLUGIN_PATH = "plugins" - PLUGINS = ["list", "of", "plugins"] + When experimenting with different plugins (especially the ones that + deal with metadata and content) caching may interfere and the + changes may not be visible. In such cases disable caching with + ``LOAD_CONTENT_CACHE = False`` or use the ``--ignore-cache`` + command-line switch. + +If your plugins are not in an importable path, you can specify a list of paths +via the ``PLUGIN_PATHS`` setting. As shown in the following example, paths in +the ``PLUGIN_PATHS`` list can be absolute or relative to the settings file:: + + PLUGIN_PATHS = ["plugins", "/srv/pelican/plugins"] + PLUGINS = ["assets", "liquid_tags", "sitemap"] + +Where to find plugins +===================== + +We maintain a separate repository of plugins for people to share and use. +Please visit the `pelican-plugins`_ repository for a list of available plugins. + +.. _pelican-plugins: https://github.com/getpelican/pelican-plugins + +Please note that while we do our best to review and maintain these plugins, +they are submitted by the Pelican community and thus may have varying levels of +support and interoperability. How to create plugins ===================== Plugins are based on the concept of signals. Pelican sends signals, and plugins -subscribe to those signals. The list of signals are defined in a following +subscribe to those signals. The list of signals are defined in a subsequent section. The only rule to follow for plugins is to define a ``register`` callable, in @@ -47,227 +65,160 @@ which you map the signals to your plugin logic. Let's take a simple example:: def register(): signals.initialized.connect(test) +.. note:: + Signal receivers are weakly-referenced and thus must not be defined within + your ``register`` callable or they will be garbage-collected before the + signal is emitted. List of signals =============== Here is the list of currently implemented signals: -========================= ============================ =========================================================================== -Signal Arguments Description -========================= ============================ =========================================================================== -initialized pelican object -finalized pelican object invoked after all the generators are executed and just before pelican exits - usefull for custom post processing actions, such as: - - minifying js/css assets. - - notify/ping search engines with an updated sitemap. -article_generate_context article_generator, metadata -article_generator_init article_generator invoked in the ArticlesGenerator.__init__ -get_generators generators invoked in Pelican.get_generator_classes, - can return a Generator, or several - generator in a tuple or in a list. -pages_generate_context pages_generator, metadata -pages_generator_init pages_generator invoked in the PagesGenerator.__init__ -========================= ============================ =========================================================================== +================================= ============================ =========================================================================== +Signal Arguments Description +================================= ============================ =========================================================================== +initialized pelican object +finalized pelican object invoked after all the generators are executed and just before pelican exits + useful for custom post processing actions, such as: + - minifying js/css assets. + - notify/ping search engines with an updated sitemap. +generator_init generator invoked in the Generator.__init__ +readers_init readers invoked in the Readers.__init__ +article_generator_context article_generator, metadata +article_generator_preread article_generator invoked before a article is read in ArticlesGenerator.generate_context; + use if code needs to do something before every article is parsed +article_generator_init article_generator invoked in the ArticlesGenerator.__init__ +article_generator_pretaxonomy article_generator invoked before categories and tags lists are created + useful when e.g. modifying the list of articles to be generated + so that removed articles are not leaked in categories or tags +article_generator_finalized article_generator invoked at the end of ArticlesGenerator.generate_context +article_generator_write_article article_generator, content invoked before writing each article, the article is passed as content +article_writer_finalized article_generator, writer invoked after all articles and related pages have been written, but before + the article generator is closed. +get_generators pelican object invoked in Pelican.get_generator_classes, + can return a Generator, or several + generators in a tuple or in a list. +get_writer pelican object invoked in Pelican.get_writer, + can return a custom Writer. +page_generator_context page_generator, metadata +page_generator_preread page_generator invoked before a page is read in PageGenerator.generate_context; + use if code needs to do something before every page is parsed. +page_generator_init page_generator invoked in the PagesGenerator.__init__ +page_generator_finalized page_generator invoked at the end of PagesGenerator.generate_context +static_generator_context static_generator, metadata +static_generator_preread static_generator invoked before a static file is read in StaticGenerator.generate_context; + use if code needs to do something before every static file is added to the + staticfiles list. +static_generator_init static_generator invoked in the StaticGenerator.__init__ +static_generator_finalized static_generator invoked at the end of StaticGenerator.generate_context +content_object_init content_object invoked at the end of Content.__init__ (see note below) +content_written path, context invoked each time a content file is written. +feed_written path, context, feed invoked each time a feed file is written. +================================= ============================ =========================================================================== -The list is currently small, don't hesitate to add signals and make a pull +The list is currently small, so don't hesitate to add signals and make a pull request if you need them! -.. note:: - - The signal ``content_object_init`` can send different type of object as - argument. If you want to register only one type of object then you will +.. note:: + + The signal ``content_object_init`` can send a different type of object as + the argument. If you want to register only one type of object then you will need to specify the sender when you are connecting to the signal. - + :: - + from pelican import signals from pelican import contents - + def test(sender, instance): print "%s : %s content initialized !!" % (sender, instance) - + def register(): signals.content_object_init.connect(test, sender=contents.Article) - - - -List of plugins -=============== - -The following plugins are currently included with Pelican under ``pelican.plugins``: - -* `GitHub activity`_ -* `Global license`_ -* `Gravatar`_ -* `HTML tags for reStructuredText`_ -* `Related posts`_ -* `Sitemap`_ - -Ideas for plugins that haven't been written yet: - -* Tag cloud -* Translation - -Plugin descriptions -=================== - -GitHub activity ---------------- - -This plugin makes use of the ``feedparser`` library that you'll need to -install. - -Set the ``GITHUB_ACTIVITY_FEED`` parameter to your GitHub activity feed. -For example, my setting would look like:: - - GITHUB_ACTIVITY_FEED = 'https://github.com/kpanic.atom' - -On the templates side, you just have to iterate over the ``github_activity`` -variable, as in the example:: - - {% if GITHUB_ACTIVITY_FEED %} - - {% endif %} - - - -``github_activity`` is a list of lists. The first element is the title -and the second element is the raw HTML from GitHub. - -Global license --------------- - -This plugin allows you to define a LICENSE setting and adds the contents of that -license variable to the article's context, making that variable available to use -from within your theme's templates. - -Gravatar --------- - -This plugin assigns the ``author_gravatar`` variable to the Gravatar URL and -makes the variable available within the article's context. You can add -AUTHOR_EMAIL to your settings file to define the default author's email -address. Obviously, that email address must be associated with a Gravatar -account. - -Alternatively, you can provide an email address from within article metadata:: - - :email: john.doe@example.com - -If the email address is defined via at least one of the two methods above, -the ``author_gravatar`` variable is added to the article's context. - -HTML tags for reStructuredText ------------------------------- - -This plugin allows you to use HTML tags from within reST documents. Following -is a usage example, which is in this case a contact form:: - - .. html:: - -
-

- -
- -
- -

-
- -Related posts -------------- - -This plugin adds the ``related_posts`` variable to the article's context. -To enable, add the following to your settings file:: - - from pelican.plugins import related_posts - PLUGINS = [related_posts] - -You can then use the ``article.related_posts`` variable in your templates. -For example:: - - {% if article.related_posts %} -
    - {% for related_post in article.related_posts %} -
  • {{ related_post }}
  • - {% endfor %} -
- {% endif %} - -Sitemap -------- - -The sitemap plugin generates plain-text or XML sitemaps. You can use the -``SITEMAP`` variable in your settings file to configure the behavior of the -plugin. - -The ``SITEMAP`` variable must be a Python dictionary, it can contain three keys: - -- ``format``, which sets the output format of the plugin (``xml`` or ``txt``) - -- ``priorities``, which is a dictionary with three keys: - - - ``articles``, the priority for the URLs of the articles and their - translations - - - ``pages``, the priority for the URLs of the static pages - - - ``indexes``, the priority for the URLs of the index pages, such as tags, - author pages, categories indexes, archives, etc... - - All the values of this dictionary must be decimal numbers between ``0`` and ``1``. - -- ``changefreqs``, which is a dictionary with three items: - - - ``articles``, the update frequency of the articles - - - ``pages``, the update frequency of the pages - - - ``indexes``, the update frequency of the index pages - - Valid frequency values are ``always``, ``hourly``, ``daily``, ``weekly``, ``monthly``, - ``yearly`` and ``never``. - -If a key is missing or a value is incorrect, it will be replaced with the -default value. - -The sitemap is saved in ``/sitemap.``. .. note:: - ``priorities`` and ``changefreqs`` are informations for search engines. - They are only used in the XML sitemaps. - For more information: -**Example** + After Pelican 3.2, signal names were standardized. Older plugins + may need to be updated to use the new names: -Here is an example configuration (it's also the default settings): + ========================== =========================== + Old name New name + ========================== =========================== + article_generate_context article_generator_context + article_generate_finalized article_generator_finalized + article_generate_preread article_generator_preread + pages_generate_context page_generator_context + pages_generate_preread page_generator_preread + pages_generator_finalized page_generator_finalized + pages_generator_init page_generator_init + static_generate_context static_generator_context + static_generate_preread static_generator_preread + ========================== =========================== -.. code-block:: python +Recipes +======= - PLUGINS=['pelican.plugins.sitemap',] +We eventually realised some of the recipes to create plugins would be best +shared in the documentation somewhere, so here they are! - SITEMAP = { - 'format': 'xml', - 'priorities': { - 'articles': 0.5, - 'indexes': 0.5, - 'pages': 0.5 - }, - 'changefreqs': { - 'articles': 'monthly', - 'indexes': 'daily', - 'pages': 'monthly' - } - } +How to create a new reader +-------------------------- + +One thing you might want is to add support for your very own input format. +While it might make sense to add this feature in Pelican core, we +wisely chose to avoid this situation and instead have the different readers +defined via plugins. + +The rationale behind this choice is mainly that plugins are really easy to +write and don't slow down Pelican itself when they're not active. + +No more talking — here is an example:: + + from pelican import signals + from pelican.readers import BaseReader + + # Create a new reader class, inheriting from the pelican.reader.BaseReader + class NewReader(BaseReader): + enabled = True # Yeah, you probably want that :-) + + # The list of file extensions you want this reader to match with. + # If multiple readers were to use the same extension, the latest will + # win (so the one you're defining here, most probably). + file_extensions = ['yeah'] + + # You need to have a read method, which takes a filename and returns + # some content and the associated metadata. + def read(self, filename): + metadata = {'title': 'Oh yeah', + 'category': 'Foo', + 'date': '2012-12-01'} + + parsed = {} + for key, value in metadata.items(): + parsed[key] = self.process_metadata(key, value) + + return "Some content", parsed + + def add_reader(readers): + readers.reader_classes['yeah'] = NewReader + + # This is how pelican works. + def register(): + signals.readers_init.connect(add_reader) + + +Adding a new generator +---------------------- + +Adding a new generator is also really easy. You might want to have a look at +:doc:`internals` for more information on how to create your own generator. + +:: + + def get_generators(pelican_object): + # define a new generator here if you need to + return MyGenerator + + signals.get_generators.connect(get_generators) diff --git a/docs/publish.rst b/docs/publish.rst new file mode 100644 index 00000000..fea053bf --- /dev/null +++ b/docs/publish.rst @@ -0,0 +1,181 @@ +Publish your site +################# + +Site generation +=============== + +Once Pelican is installed and you have some content (e.g., in Markdown or reST +format), you can convert your content into HTML via the ``pelican`` command, +specifying the path to your content and (optionally) the path to your +:doc:`settings` file:: + + pelican /path/to/your/content/ [-s path/to/your/settings.py] + +The above command will generate your site and save it in the ``output/`` +folder, using the default theme to produce a simple site. The default theme +consists of very simple HTML without styling and is provided so folks may use +it as a basis for creating their own themes. + +You can also tell Pelican to watch for your modifications, instead of +manually re-running it every time you want to see your changes. To enable this, +run the ``pelican`` command with the ``-r`` or ``--autoreload`` option. + +Pelican has other command-line switches available. Have a look at the help to +see all the options you can use:: + + pelican --help + +Viewing the generated files +--------------------------- + +The files generated by Pelican are static files, so you don't actually need +anything special to view them. You can use your browser to open the generated +HTML files directly:: + + firefox output/index.html + +Because the above method may have trouble locating your CSS and other linked +assets, running a simple web server using Python will often provide a more +reliable previewing experience. + +For Python 2, run:: + + cd output + python -m SimpleHTTPServer + +For Python 3, run:: + + cd output + python -m http.server + +Once the basic server has been started, you can preview your site at +http://localhost:8000/ + +Deployment +========== + +After you have generated your site, previewed it in your local development +environment, and are ready to deploy it to production, you might first +re-generate your site with any production-specific settings (e.g., analytics +feeds, etc.) that you may have defined:: + + pelican content -s publishconf.py + +The steps for deploying your site will depend on where it will be hosted. +If you have SSH access to a server running Nginx or Apache, you might use the +``rsync`` tool to transmit your site files:: + + rsync --avc --delete output/ host.example.com:/var/www/your-site/ + +There are many other deployment options, some of which can be configured when +first setting up your site via the ``pelican-quickstart`` command. See the +:doc:`Tips` page for detail on publishing via GitHub Pages. + +Automation +========== + +While the ``pelican`` command is the canonical way to generate your site, +automation tools can be used to streamline the generation and publication +flow. One of the questions asked during the ``pelican-quickstart`` process +pertains to whether you want to automate site generation and publication. +If you answered "yes" to that question, a ``fabfile.py`` and +``Makefile`` will be generated in the root of your project. These files, +pre-populated with certain information gleaned from other answers provided +during the ``pelican-quickstart`` process, are meant as a starting point and +should be customized to fit your particular needs and usage patterns. If you +find one or both of these automation tools to be of limited utility, these +files can deleted at any time and will not affect usage of the canonical +``pelican`` command. + +Following are automation tools that "wrap" the ``pelican`` command and can +simplify the process of generating, previewing, and uploading your site. + +Fabric +------ + +The advantage of Fabric_ is that it is written in Python and thus can be used +in a wide range of environments. The downside is that it must be installed +separately. Use the following command to install Fabric, prefixing with +``sudo`` if your environment requires it:: + + pip install Fabric + +Take a moment to open the ``fabfile.py`` file that was generated in your +project root. You will see a number of commands, any one of which can be +renamed, removed, and/or customized to your liking. Using the out-of-the-box +configuration, you can generate your site via:: + + fab build + +If you'd prefer to have Pelican automatically regenerate your site every time a +change is detected (which is handy when testing locally), use the following +command instead:: + + fab regenerate + +To serve the generated site so it can be previewed in your browser at +http://localhost:8000/:: + + fab serve + +If during the ``pelican-quickstart`` process you answered "yes" when asked +whether you want to upload your site via SSH, you can use the following command +to publish your site via rsync over SSH:: + + fab publish + +These are just a few of the commands available by default, so feel free to +explore ``fabfile.py`` and see what other commands are available. More +importantly, don't hesitate to customize ``fabfile.py`` to suit your specific +needs and preferences. + +Make +---- + +A ``Makefile`` is also automatically created for you when you say "yes" to +the relevant question during the ``pelican-quickstart`` process. The advantage +of this method is that the ``make`` command is built into most POSIX systems +and thus doesn't require installing anything else in order to use it. The +downside is that non-POSIX systems (e.g., Windows) do not include ``make``, +and installing it on those systems can be a non-trivial task. + +If you want to use ``make`` to generate your site, run:: + + make html + +If you'd prefer to have Pelican automatically regenerate your site every time a +change is detected (which is handy when testing locally), use the following +command instead:: + + make regenerate + +To serve the generated site so it can be previewed in your browser at +http://localhost:8000/:: + + make serve + +Normally you would need to run ``make regenerate`` and ``make serve`` in two +separate terminal sessions, but you can run both at once via:: + + make devserver + +The above command will simultaneously run Pelican in regeneration mode as well +as serve the output at http://localhost:8000. Once you are done testing your +changes, you should stop the development server via:: + + ./develop_server.sh stop + +When you're ready to publish your site, you can upload it via the method(s) you +chose during the ``pelican-quickstart`` questionnaire. For this example, we'll +use rsync over ssh:: + + make rsync_upload + +That's it! Your site should now be live. + +(The default ``Makefile`` and ``devserver.sh`` scripts use the ``python`` and +``pelican`` executables to complete its tasks. If you want to use different +executables, such as ``python3``, you can set the ``PY`` and ``PELICAN`` +environment variables, respectively, to override the default executable names.) + +.. _Fabric: http://fabfile.org/ diff --git a/docs/quickstart.rst b/docs/quickstart.rst new file mode 100644 index 00000000..4fe75d98 --- /dev/null +++ b/docs/quickstart.rst @@ -0,0 +1,74 @@ +Quickstart +########## + +Reading through all the documentation is highly recommended, but for the truly +impatient, following are some quick steps to get started. + +Installation +------------ + +Install Pelican (and optionally Markdown if you intend to use it) on Python +2.7.x or Python 3.3+ by running the following command in your preferred +terminal, prefixing with ``sudo`` if permissions warrant:: + + pip install pelican markdown + +Create a project +---------------- + +First, choose a name for your project, create an appropriately-named directory +for your site, and switch to that directory:: + + mkdir -p ~/projects/yoursite + cd ~/projects/yoursite + +Create a skeleton project via the ``pelican-quickstart`` command, which begins +by asking some questions about your site:: + + pelican-quickstart + +For questions that have default values denoted in brackets, feel free to use +the Return key to accept those default values. When asked for your URL prefix, +enter your domain name as indicated (e.g., ``http://example.com``). + +Create an article +----------------- + +You cannot run Pelican until you have created some content. Use your preferred +text editor to create your first article with the following content:: + + Title: My First Review + Date: 2010-12-03 10:20 + Category: Review + + Following is a review of my favorite mechanical keyboard. + +Given that this example article is in Markdown format, save it as +``~/projects/yoursite/content/keyboard-review.md``. + +Generate your site +------------------ + +From your project directory, run the ``pelican`` command to generate your site:: + + pelican content + +Your site has now been generated inside the ``output`` directory. (You may see a +warning related to feeds, but that is normal when developing locally and can be +ignored for now.) + +Preview your site +----------------- + +Open a new terminal session and run the following commands to switch to your +``output`` directory and launch Python's built-in web server:: + + cd ~/projects/yoursite/output + python -m SimpleHTTPServer + +Preview your site by navigating to http://localhost:8000/ in your browser. + +Continue reading the other documentation sections for more detail, and check out +the Pelican wiki's Tutorials_ page for links to community-published tutorials. + +.. _Tutorials: https://github.com/getpelican/pelican/wiki/Tutorials diff --git a/docs/settings.rst b/docs/settings.rst index ff59e0d3..02f4359f 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -1,14 +1,25 @@ Settings ######## -Pelican is configurable thanks to a configuration file you can pass to +Pelican is configurable thanks to a settings file you can pass to the command line:: - $ pelican -s path/to/your/settingsfile.py path + pelican content -s path/to/your/pelicanconf.py -Settings are configured in the form of a Python module (a file). You can see an -example by looking at `/samples/pelican.conf.py +(If you used the ``pelican-quickstart`` command, your primary settings file will +be named ``pelicanconf.py`` by default.) + +.. note:: + + When experimenting with different settings (especially the metadata + ones) caching may interfere and the changes may not be visible. In + such cases disable caching with ``LOAD_CONTENT_CACHE = False`` or + use the ``--ignore-cache`` command-line switch. + +Settings are configured in the form of a Python module (a file). There is an +`example settings file `_ +available for reference. All the setting identifiers must be set in all-caps, otherwise they will not be processed. Setting values that are numbers (5, 20, etc.), booleans (True, @@ -16,137 +27,226 @@ False, None, etc.), dictionaries, or tuples should *not* be enclosed in quotation marks. All other values (i.e., strings) *must* be enclosed in quotation marks. -Unless otherwise specified, settings that refer to paths can be either absolute or relative to the -configuration file. +Unless otherwise specified, settings that refer to paths can be either absolute +or relative to the configuration file. The settings you define in the configuration file will be passed to the templates, which allows you to use your settings to add site-wide content. Here is a list of settings for Pelican: + Basic settings ============== -===================================================================== ===================================================================== -Setting name (default value) What does it do? -===================================================================== ===================================================================== -`AUTHOR` Default author (put your name) -`DATE_FORMATS` (``{}``) If you do manage multiple languages, you can - set the date formatting here. See "Date format and locales" - section below for details. -`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 - template. Templates may or not honor this - setting. -`DEFAULT_DATE` (``fs``) The default date you want to use. - If 'fs', Pelican will use the file system - timestamp information (mtime) if it can't get - date information from the metadata. - If tuple object, it will instead generate the - default datetime object by passing the tuple to - the datetime.datetime constructor. -`JINJA_EXTENSIONS` (``[]``) A list of any Jinja2 extensions you want to use. -`DELETE_OUTPUT_DIRECTORY` (``False``) Delete the content of the output directory before - generating new files. -`LOCALE` (''[#]_) Change the locale. A list of locales can be provided - here or a single string representing one locale. - When providing a list, all the locales will be tried - until one works. -`MARKUP` (``('rst', 'md')``) A list of available markup languages you want - to use. For the moment, the only available values - are `rst` and `md`. -`MD_EXTENSIONS` (``['codehilite','extra']``) A list of the extensions that the Markdown processor - will use. Refer to the extensions chapter in the - Python-Markdown documentation for a complete list of - supported extensions. -`OUTPUT_PATH` (``'output/'``) Where to output the generated files. -`PATH` (``None``) Path to content directory to be processed by Pelican. -`PAGE_DIR` (``'pages'``) Directory to look at for pages, relative to `PATH`. -`PAGE_EXCLUDES` (``()``) A list of directories to exclude when looking for pages. -`ARTICLE_DIR` (``''``) Directory to look at for articles, relative to `PATH`. -`ARTICLE_EXCLUDES`: (``('pages',)``) A list of directories to exclude when looking for articles. -`PDF_GENERATOR` (``False``) Set to True if you want to have PDF versions - of your documents. You will need to install - `rst2pdf`. -`OUTPUT_SOURCES` (``False``) Set to True if you want to copy the articles and pages in their - original format (e.g. Markdown or ReStructeredText) to the - specified OUTPUT_PATH. -`OUTPUT_SOURCES_EXTENSION` (``.text``) Controls the extension that will be used by the SourcesGenerator. - Defaults to ``.text``. If not a valid string the default value - will be used. -`RELATIVE_URLS` (``True``) Defines whether Pelican should use document-relative URLs or - not. If set to ``False``, Pelican will use the SITEURL - setting to construct absolute URLs. -`PLUGINS` (``[]``) The list of plugins to load. See :ref:`plugins`. -`SITENAME` (``'A Pelican Blog'``) Your site name -`SITEURL` Base URL of your website. Not defined by default, - so it is best to specify your SITEURL; if you do not, feeds - will not be generated with properly-formed URLs. You should - include ``http://`` and your domain, with no trailing - slash at the end. Example: ``SITEURL = 'http://mydomain.com'`` -`STATIC_PATHS` (``['images']``) The static paths you want to have accessible - on the output path "static". By default, - Pelican will copy the 'images' folder to the - output folder. -`TIMEZONE` The timezone used in the date information, to - generate Atom and RSS feeds. See the "timezone" - section below for more info. -`TYPOGRIFY` (``False``) If set to True, several typographical improvements will be - incorporated into the generated HTML via the `Typogrify - `_ - library, which can be installed via: ``pip install typogrify`` -`LESS_GENERATOR` (``FALSE``) Set to True or complete path to `lessc` (if not - found in system PATH) to enable compiling less - css files. Requires installation of `less css`_. -`DIRECT_TEMPLATES` (``('index', 'tags', 'categories', 'archives')``) List of templates that are used directly to render - content. Typically direct templates are used to generate - index pages for collections of content e.g. tags and - category index pages. -`PAGINATED_DIRECT_TEMPLATES` (``('index',)``) Provides the direct templates that should be paginated. -`SUMMARY_MAX_LENGTH` (``50``) When creating a short summary of an article, this will - be the default length in words of the text created. - This only applies if your content does not otherwise - specify a summary. Setting to None will cause the summary - to be a copy of the original content. -`EXTRA_TEMPLATES_PATHS` (``[]``) A list of paths you want Jinja2 to look for the templates. - Can be used to separate templates from the theme. - Example: projects, resume, profile ... - This templates need to use ``DIRECT_TEMPLATES`` setting - -`MARKDOWN_EXTENSIONS` (``['toc',]``) A list of any Markdown extensions you want to use. -===================================================================== ===================================================================== +=============================================================================== ===================================================================== +Setting name (followed by default value, if any) What does it do? +=============================================================================== ===================================================================== +``AUTHOR`` Default author (put your name) +``DATE_FORMATS = {}`` If you manage multiple languages, you can set the date formatting + here. See the "Date format and locale" section below for details. +``USE_FOLDER_AS_CATEGORY = True`` When you don't specify a category in your post metadata, 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 + template. Templates may or may not honor this + setting. +``DISPLAY_CATEGORIES_ON_MENU = True`` Whether to display categories on the menu of the + template. Templates may or not honor this + setting. +``DEFAULT_DATE = None`` The default date you want to use. + If ``fs``, Pelican will use the file system + timestamp information (mtime) if it can't get + date information from the metadata. + If set to a tuple object, the default datetime object will instead + be generated by passing the tuple to the + ``datetime.datetime`` constructor. +``DEFAULT_METADATA = ()`` The default metadata you want to use for all articles + and pages. +``DOCUTILS_SETTINGS = {}`` Extra configuration settings for the docutils publisher + (applicable only to reStructuredText). See `Docutils + Configuration`_ settings for more details. + +``FILENAME_METADATA =`` ``'(?P\d{4}-\d{2}-\d{2}).*'`` The regexp that will be used to extract any metadata + from the filename. All named groups that are matched + will be set in the metadata object. + The default value will only extract the date from + the filename. + For example, if you would like to extract both the + date and the slug, you could set something like: + ``'(?P\d{4}-\d{2}-\d{2})_(?P.*)'``. + See :ref:`path_metadata` and ``SLUGIFY_SOURCE``. +``PATH_METADATA = ''`` Like ``FILENAME_METADATA``, but parsed from a page's + full path relative to the content source directory. + See :ref:`path_metadata`. +``EXTRA_PATH_METADATA = {}`` Extra metadata dictionaries keyed by relative path. Relative paths + require correct OS-specific directory separators (i.e. / in UNIX and + \\ in Windows) unlike some other Pelican file settings. + See :ref:`path_metadata`. +``DELETE_OUTPUT_DIRECTORY = False`` Delete the output directory, and **all** of its contents, before + generating new files. This can be useful in preventing older, + unnecessary files from persisting in your output. However, **this is + a destructive setting and should be handled with extreme care.** +``OUTPUT_RETENTION = ()`` A tuple of filenames that should be retained and not deleted from the + output directory. One use case would be the preservation of version + control data. For example: ``(".hg", ".git", ".bzr")`` +``JINJA_EXTENSIONS = []`` A list of any Jinja2 extensions you want to use. +``JINJA_FILTERS = {}`` A list of custom Jinja2 filters you want to use. + The dictionary should map the filtername to the filter function. + For example: ``{'urlencode': urlencode_filter}`` + See `Jinja custom filters documentation`_. +``LOCALE`` [#]_ Change the locale. A list of locales can be provided + here or a single string representing one locale. + When providing a list, all the locales will be tried + until one works. +``LOG_FILTER = []`` A list of tuples containing the logging level (up to ``warning``) + and the message to be ignored. + For example: ``[(logging.WARN, 'TAG_SAVE_AS is set to False')]`` +``READERS = {}`` A dictionary of file extensions / Reader classes for Pelican to + process or ignore. For example, to avoid processing .html files, + set: ``READERS = {'html': None}``. To add a custom reader for the + ``foo`` extension, set: ``READERS = {'foo': FooReader}`` +``IGNORE_FILES = ['.#*']`` A list of file globbing patterns to match against the + source files to be ignored by the processor. For example, + the default ``['.#*']`` will ignore emacs lock files. +``MD_EXTENSIONS =`` ``['codehilite(css_class=highlight)','extra']`` A list of the extensions that the Markdown processor + will use. Refer to the Python Markdown documentation's + `Extensions section `_ + for a complete list of supported extensions. (Note that + defining this in your settings file will override and + replace the default values. If your goal is to *add* + to the default values for this setting, you'll need to + include them explicitly and enumerate the full list of + desired Markdown extensions.) +``OUTPUT_PATH = 'output/'`` Where to output the generated files. +``PATH`` Path to content directory to be processed by Pelican. If undefined, + and content path is not specified via an argument to the ``pelican`` + command, Pelican will use the current working directory. +``PAGE_PATHS = ['pages']`` A list of directories and files to look at for pages, + relative to ``PATH``. +``PAGE_EXCLUDES = []`` A list of directories to exclude when looking for pages in addition + to ``ARTICLE_PATHS``. +``ARTICLE_PATHS = ['']`` A list of directories and files to look at for articles, + relative to ``PATH``. +``ARTICLE_EXCLUDES = []`` A list of directories to exclude when looking for articles in addition + to ``PAGE_PATHS``. +``OUTPUT_SOURCES = False`` Set to True if you want to copy the articles and pages in their + original format (e.g. Markdown or reStructuredText) to the + specified ``OUTPUT_PATH``. +``OUTPUT_SOURCES_EXTENSION = '.text'`` Controls the extension that will be used by the SourcesGenerator. + Defaults to ``.text``. If not a valid string the default value + will be used. +``RELATIVE_URLS = False`` Defines whether Pelican should use document-relative URLs or + not. Only set this to ``True`` when developing/testing and only + if you fully understand the effect it can have on links/feeds. +``PLUGINS = []`` The list of plugins to load. See :ref:`plugins`. +``PLUGIN_PATHS = []`` A list of directories where to look for plugins. See :ref:`plugins`. +``SITENAME = 'A Pelican Blog'`` Your site name +``SITEURL`` Base URL of your website. Not defined by default, + so it is best to specify your SITEURL; if you do not, feeds + will not be generated with properly-formed URLs. You should + include ``http://`` and your domain, with no trailing + slash at the end. Example: ``SITEURL = 'http://mydomain.com'`` +``TEMPLATE_PAGES = None`` A mapping containing template pages that will be rendered with + the blog entries. See :ref:`template_pages`. +``STATIC_PATHS = ['images']`` A list of directories (relative to ``PATH``) in which to look for + static files. Such files will be copied to the output directory + without modification. Articles, pages, and other content source + files will normally be skipped, so it is safe for a directory to + appear both here and in ``PAGE_PATHS`` or ``ARTICLE_PATHS``. + Pelican's default settings include the "images" directory here. +``STATIC_EXCLUDES = []`` A list of directories to exclude when looking for static files. +``STATIC_EXCLUDE_SOURCES = True`` If set to False, content source files will not be skipped when + copying files found in ``STATIC_PATHS``. +``TIMEZONE`` The timezone used in the date information, to + generate Atom and RSS feeds. See the *Timezone* + section below for more info. +``TYPOGRIFY = False`` If set to True, several typographical improvements will be + incorporated into the generated HTML via the `Typogrify + `_ library, + which can be installed via: ``pip install typogrify`` +``TYPOGRIFY_IGNORE_TAGS = []`` A list of tags for Typogrify to ignore. By default + Typogrify will ignore ``pre`` and ``code`` tags. This + requires that Typogrify version 2.0.4 or later is installed +``DIRECT_TEMPLATES =`` ``('index', 'categories', 'authors', 'archives')`` List of templates that are used directly to render + content. Typically direct templates are used to generate + index pages for collections of content (e.g., tags and + category index pages). If the tag and category collections + are not needed, set ``DIRECT_TEMPLATES = ('index', 'archives')`` +``PAGINATED_DIRECT_TEMPLATES = ('index',)`` Provides the direct templates that should be paginated. +``SUMMARY_MAX_LENGTH = 50`` When creating a short summary of an article, this will + be the default length (measured in words) of the text created. + This only applies if your content does not otherwise + specify a summary. Setting to ``None`` will cause the summary + to be a copy of the original content. +``EXTRA_TEMPLATES_PATHS = []`` A list of paths you want Jinja2 to search for templates. + Can be used to separate templates from the theme. + Example: projects, resume, profile ... + These templates need to use ``DIRECT_TEMPLATES`` setting. +``WITH_FUTURE_DATES = True`` If disabled, content with dates in the future will get a default + status of ``draft``. See :ref:`reading_only_modified_content` + for caveats. +``INTRASITE_LINK_REGEX = '[{|](?P.*?)[|}]'`` Regular expression that is used to parse internal links. Default + syntax when linking to internal files, tags, etc., is to enclose + the identifier, say ``filename``, in ``{}`` or ``||``. Identifier + between ``{`` and ``}`` goes into the ``what`` capturing group. + For details see :ref:`ref-linking-to-internal-content`. +``PYGMENTS_RST_OPTIONS = []`` A list of default Pygments settings for your reStructuredText + code blocks. See :ref:`internal_pygments_options` for a list of + supported options. +``SLUGIFY_SOURCE = 'title'`` Specifies where you want the slug to be automatically generated + from. Can be set to ``title`` to use the 'Title:' metadata tag or + ``basename`` to use the article's file name when creating the slug. +``CACHE_CONTENT = True`` If ``True``, save content in a cache file. + See :ref:`reading_only_modified_content` for details about caching. +``CONTENT_CACHING_LAYER = 'reader'`` If set to ``'reader'``, save only the raw content and metadata + returned by readers. If set to ``'generator'``, save processed + content objects. +``CACHE_PATH = 'cache'`` Directory in which to store cache files. +``GZIP_CACHE = True`` If ``True``, use gzip to (de)compress the cache files. +``CHECK_MODIFIED_METHOD = 'mtime'`` Controls how files are checked for modifications. +``LOAD_CONTENT_CACHE = True`` If ``True``, load unmodified content from cache. +``AUTORELOAD_IGNORE_CACHE = False`` If ``True``, do not load content cache in autoreload mode + when the settings file changes. +``WRITE_SELECTED = []`` If this list is not empty, **only** output files with their paths + in this list are written. Paths should be either absolute or relative + to the current Pelican working directory. For possible use cases see + :ref:`writing_only_selected_content`. +=============================================================================== ===================================================================== .. [#] Default is the system locale. -.. _less css: http://lesscss.org/ - URL settings ------------- +============ The first thing to understand is that there are currently two supported methods -for URL formation: *relative* and *absolute*. Document-relative URLs are useful +for URL formation: *relative* and *absolute*. Relative URLs are useful when testing locally, and absolute URLs are reliable and most useful when publishing. One method of supporting both is to have one Pelican configuration file for local development and another for publishing. To see an example of this -type of setup, use the ``pelican-quickstart`` script as described at the top of -the :doc:`Getting Started` page, which will produce two separate +type of setup, use the ``pelican-quickstart`` script as described in the +:doc:`Installation ` section, which will produce two separate configuration files for local development and publishing, respectively. -You can customize the URLs and locations where files will be saved. The URLs 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 them as -'{slug}' for clean URLs. These settings give you the flexibility to place your -articles and pages anywhere you want. +You can customize the URLs and locations where files will be saved. The +``*_URL`` 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 them as ``{slug}`` for clean URLs (see +example below). 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 + 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 - particular file, Pelican will rely on the file's mtime timestamp. + particular file, Pelican will rely on the file's ``mtime`` timestamp. + Check the `Python datetime documentation`_ for more information. -Check the Python datetime documentation at http://bit.ly/cNcJUC for more -information. +.. _Python datetime documentation: + http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior Also, you can use other file metadata attributes as well: @@ -158,41 +258,121 @@ Also, you can use other file metadata attributes as well: 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'`` +* ``ARTICLE_URL = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/'`` +* ``ARTICLE_SAVE_AS = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/index.html'`` +* ``PAGE_URL = 'pages/{slug}/'`` +* ``PAGE_SAVE_AS = 'pages/{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/'. +This would save your articles into something like ``/posts/2011/Aug/07/sample-post/index.html``, +save your pages into ``/pages/about/index.html``, and render them available at +URLs of ``/posts/2011/Aug/07/sample-post/`` and ``/pages/about/``, respectively. -==================================================== ===================================================== -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 +====================================================== ============================================================== +Setting name (followed by default value, if any) 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_ORDER_BY = 'slug'`` The metadata attribute used to sort articles. By default, + the ``articles_page.object_list`` template variable is + ordered by slug. If you modify this, make sure all + articles contain the attribute you specify. You can also + specify a "sorting" function of one argument that is used + to extract a comparison key from each article. For example, + sorting by title without using the built-in functionality + would use the function ``operator.attrgetter('title')``. +``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 +``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 +``DRAFT_URL = 'drafts/{slug}.html'`` The URL to refer to an article draft. +``DRAFT_SAVE_AS = 'drafts/{slug}.html'`` The place where we will save an article draft. +``DRAFT_LANG_URL = 'drafts/{slug}-{lang}.html'`` The URL to refer to an article draft 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 +``DRAFT_LANG_SAVE_AS = 'drafts/{slug}-{lang}.html'`` The place where we will save an article draft 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. This value has to be + the same as PAGE_URL or you need to use a rewrite in + your server config. + +``PAGE_ORDER_BY = 'basename'`` The metadata attribute used to sort pages. By default + the ``PAGES`` template variable is ordered by basename + (i.e., path not included). Note that the option ``'basename'`` + is a special option supported in the source code. If + you modify this setting, make sure all pages contain + the attribute you specify. You can also specify a "sorting" + function of one argument that is used to extract a comparison + key from each page. For example, the basename function looks + similar to + ``lambda x: os.path.basename(getattr(x, 'source_path', ''))``. +``PAGE_LANG_URL = 'pages/{slug}-{lang}.html'`` The URL we will use to link to a 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. -`_SAVE_AS` The location to save content generated from direct - templates. Where is the - upper case template name. -==================================================== ===================================================== +``PAGE_LANG_SAVE_AS = 'pages/{slug}-{lang}.html'`` The location we will save the page which doesn't + use the default language. +``CATEGORY_URL = 'category/{slug}.html'`` The URL to use for a category. +``CATEGORY_SAVE_AS = 'category/{slug}.html'`` The location to save a category. +``TAG_URL = 'tag/{slug}.html'`` The URL to use for a tag. +``TAG_SAVE_AS = 'tag/{slug}.html'`` The location to save the tag page. +``AUTHOR_URL = 'author/{slug}.html'`` The URL to use for an author. +``AUTHOR_SAVE_AS = 'author/{slug}.html'`` The location to save an author. +``YEAR_ARCHIVE_SAVE_AS = ''`` The location to save per-year archives of your posts. +``MONTH_ARCHIVE_SAVE_AS = ''`` The location to save per-month archives of your posts. +``DAY_ARCHIVE_SAVE_AS = ''`` The location to save per-day archives of your posts. +``SLUG_SUBSTITUTIONS = ()`` Substitutions to make prior to stripping out + non-alphanumerics when generating slugs. Specified + as a list of 2-tuples of ``(from, to)`` which are + applied in order. +====================================================== ============================================================== .. note:: - When any of `*_SAVE_AS` is set to False, files will not be created. + If you do not want one or more of the default pages to be created (e.g., + you are the only author on your site and thus do not need an Authors page), + set the corresponding ``*_SAVE_AS`` setting to ``''`` to prevent the + relevant page from being generated. + +Pelican can optionally create per-year, per-month, and per-day archives of your +posts. These secondary archives are disabled by default but are automatically +enabled if you supply format strings for their respective ``_SAVE_AS`` settings. +Period archives fit intuitively with the hierarchical model of web URLs and can +make it easier for readers to navigate through the posts you've written over time. + +Example usage: + +* ``YEAR_ARCHIVE_SAVE_AS = 'posts/{date:%Y}/index.html'`` +* ``MONTH_ARCHIVE_SAVE_AS = 'posts/{date:%Y}/{date:%b}/index.html'`` + +With these settings, Pelican will create an archive of all your posts for the +year at (for instance) ``posts/2011/index.html`` and an archive of all your +posts for the month at ``posts/2011/Aug/index.html``. + +.. note:: + Period archives work best when the final path segment is ``index.html``. + This way a reader can remove a portion of your URL and automatically + arrive at an appropriate archive of posts, without having to specify + a page name. + +``DIRECT_TEMPLATES``, which are ``('index', 'tags', 'categories', 'archives')`` +by default, work a bit differently than noted above. Only the ``_SAVE_AS`` +settings are available, but it is available for any direct template. + +============================================= ====================================================== +Setting name (followed by default value) What does it do? +============================================= ====================================================== +``ARCHIVES_SAVE_AS = 'archives.html'`` The location to save the article archives page. +``YEAR_ARCHIVE_SAVE_AS = ''`` The location to save per-year archives of your posts. +``MONTH_ARCHIVE_SAVE_AS = ''`` The location to save per-month archives of your posts. +``DAY_ARCHIVE_SAVE_AS = ''`` The location to save per-day archives of your posts. +``AUTHORS_SAVE_AS = 'authors.html'`` The location to save the author list. +``CATEGORIES_SAVE_AS = 'categories.html'`` The location to save the category list. +``TAGS_SAVE_AS = 'tags.html'`` The location to save the tag list. +``INDEX_SAVE_AS = 'index.html'`` The location to save the list of all articles. +============================================= ====================================================== + +URLs for direct template pages are theme-dependent. Some themes use +corresponding ``*_URL`` setting as string, while others hard-code them: +``'archives.html'``, ``'authors.html'``, ``'categories.html'``, ``'tags.html'``. + Timezone -------- @@ -211,10 +391,15 @@ Have a look at `the wikipedia page`_ to get a list of valid timezone values. Date format and locale ---------------------- -If no DATE_FORMATS is set, fall back to DEFAULT_DATE_FORMAT. If you need to -maintain multiple languages with different date formats, you can set this dict -using language name (``lang`` in your posts) as key. Regarding available format -codes, see `strftime document of python`_ : +If no ``DATE_FORMATS`` are set, Pelican will fall back to +``DEFAULT_DATE_FORMAT``. If you need to maintain multiple languages with +different date formats, you can set the ``DATE_FORMATS`` dictionary using the +language name (``lang`` metadata in your post content) as the key. + +In addition to the standard C89 strftime format codes that are listed in +`Python strftime documentation`_, you can use ``-`` character between ``%`` and +the format character to remove any leading zeros. For example, ``%d/%m/%Y`` will +output ``01/01/2014`` whereas ``%-d/%-m/%Y`` will result in ``1/1/2014``. .. parsed-literal:: @@ -232,8 +417,8 @@ You can set locale to further control date format: ) Also, it is possible to set different locale settings for each language. If you -put (locale, format) tuples in the dict, this will override the LOCALE setting -above: +put (locale, format) tuples in the dict, this will override the ``LOCALE`` +setting above: .. parsed-literal:: # On Unix/Linux @@ -253,12 +438,78 @@ can get a list of available locales via the ``locale -a`` command; see manpage `locale(1)`_ for more information. -.. _strftime document of python: http://docs.python.org/library/datetime.html#strftime-strptime-behavior +.. _Python strftime documentation: http://docs.python.org/library/datetime.html#strftime-strptime-behavior .. _locales on Windows: http://msdn.microsoft.com/en-us/library/cdax410z%28VS.71%29.aspx .. _locale(1): http://linux.die.net/man/1/locale + +.. _template_pages: + + +Template pages +============== + +If you want to generate custom pages besides your blog entries, you can point +any Jinja2 template file with a path pointing to the file and the destination +path for the generated file. + +For instance, if you have a blog with three static pages — a list of books, +your resume, and a contact page — you could have:: + + TEMPLATE_PAGES = {'src/books.html': 'dest/books.html', + 'src/resume.html': 'dest/resume.html', + 'src/contact.html': 'dest/contact.html'} + + +.. _path_metadata: + + +Path metadata +============= + +Not all metadata needs to be `embedded in source file itself`__. For +example, blog posts are often named following a ``YYYY-MM-DD-SLUG.rst`` +pattern, or nested into ``YYYY/MM/DD-SLUG`` directories. To extract +metadata from the filename or path, set ``FILENAME_METADATA`` or +``PATH_METADATA`` to regular expressions that use Python's `group name +notation`_ ``(?P…)``. If you want to attach additional metadata +but don't want to encode it in the path, you can set +``EXTRA_PATH_METADATA``: + +.. parsed-literal:: + + EXTRA_PATH_METADATA = { + 'relative/path/to/file-1': { + 'key-1a': 'value-1a', + 'key-1b': 'value-1b', + }, + 'relative/path/to/file-2': { + 'key-2': 'value-2', + }, + } + +This can be a convenient way to shift the installed location of a +particular file: + +.. parsed-literal:: + + # Take advantage of the following defaults + # STATIC_SAVE_AS = '{path}' + # STATIC_URL = '{path}' + STATIC_PATHS = [ + 'static/robots.txt', + ] + EXTRA_PATH_METADATA = { + 'static/robots.txt': {'path': 'robots.txt'}, + } + +__ internal_metadata__ +.. _group name notation: + http://docs.python.org/3/library/re.html#regular-expression-syntax + + Feed settings ============= @@ -269,32 +520,39 @@ Pelican generates category feeds as well as feeds for all your articles. It does not generate feeds for tags by default, but it is possible to do so using the ``TAG_FEED_ATOM`` and ``TAG_FEED_RSS`` settings: -================================================ ===================================================== -Setting name (default value) What does it do? -================================================ ===================================================== -`FEED_DOMAIN` (``None``, i.e. base URL is "/") The domain prepended to feed URLs. Since feed URLs +================================================= ===================================================== +Setting name (followed by default value, if any) What does it do? +================================================= ===================================================== +``FEED_DOMAIN = None``, i.e. base URL is "/" The domain prepended to feed URLs. Since feed URLs should always be absolute, it is highly recommended to define this (e.g., "http://feeds.example.com"). If you have already explicitly defined SITEURL (see above) and want to use the same domain for your - feeds, you can just set: `FEED_DOMAIN = SITEURL` -`FEED_ATOM` (``'feeds/all.atom.xml'``) Relative URL to output the Atom feed. -`FEED_RSS` (``None``, i.e. no RSS) Relative URL to output the RSS feed. -`CATEGORY_FEED_ATOM` ('feeds/%s.atom.xml'[2]_) Where to put the category Atom feeds. -`CATEGORY_FEED_RSS` (``None``, i.e. no RSS) Where to put the category RSS feeds. -`TAG_FEED_ATOM` (``None``, i.e. no tag feed) Relative URL to output the tag Atom feed. It should + feeds, you can just set: ``FEED_DOMAIN = SITEURL``. +``FEED_ATOM = None``, i.e. no Atom feed Relative URL to output the Atom feed. +``FEED_RSS = None``, i.e. no RSS Relative URL to output the RSS feed. +``FEED_ALL_ATOM = 'feeds/all.atom.xml'`` Relative URL to output the all-posts Atom feed: + this feed will contain all posts regardless of their + language. +``FEED_ALL_RSS = None``, i.e. no all-posts RSS Relative URL to output the all-posts RSS feed: + this feed will contain all posts regardless of their + language. +``CATEGORY_FEED_ATOM = 'feeds/%s.atom.xml'`` [2]_ Where to put the category Atom feeds. +``CATEGORY_FEED_RSS = None``, i.e. no RSS Where to put the category RSS feeds. +``AUTHOR_FEED_ATOM = 'feeds/%s.atom.xml'`` [2]_ Where to put the author Atom feeds. +``AUTHOR_FEED_RSS = 'feeds/%s.rss.xml'`` [2]_ Where to put the author RSS feeds. +``TAG_FEED_ATOM = None``, i.e. no tag feed Relative URL to output the tag Atom feed. It should be defined using a "%s" match in the tag name. -`TAG_FEED_RSS` (``None``, ie no RSS tag feed) Relative URL to output the tag RSS feed -`FEED_MAX_ITEMS` Maximum number of items allowed in a feed. Feed item +``TAG_FEED_RSS = None``, i.e. no RSS tag feed Relative URL to output the tag RSS feed +``FEED_MAX_ITEMS`` Maximum number of items allowed in a feed. Feed item quantity is unrestricted by default. -================================================ ===================================================== +================================================= ===================================================== -If you don't want to generate some of these feeds, set ``None`` to the -variables above. If you don't want to generate any feeds set both ``FEED_ATOM`` -and ``FEED_RSS`` to none. +If you don't want to generate some or any of these feeds, set the above variables to ``None``. .. [2] %s is the name of the category. + FeedBurner ---------- @@ -302,39 +560,66 @@ If you want to use FeedBurner for your feed, you will likely need to decide upon a unique identifier. For example, if your site were called "Thyme" and hosted on the www.example.com domain, you might use "thymefeeds" as your unique identifier, which we'll use throughout this section for illustrative -purposes. In your Pelican settings, set the `FEED_ATOM` attribute to -"thymefeeds/main.xml" to create an Atom feed with an original address of -`http://www.example.com/thymefeeds/main.xml`. Set the `FEED_DOMAIN` attribute -to `http://feeds.feedburner.com`, or `http://feeds.example.com` if you are -using a CNAME on your own domain (i.e., FeedBurner's "MyBrand" feature). +purposes. In your Pelican settings, set the ``FEED_ATOM`` attribute to +``thymefeeds/main.xml`` to create an Atom feed with an original address of +``http://www.example.com/thymefeeds/main.xml``. Set the ``FEED_DOMAIN`` +attribute to ``http://feeds.feedburner.com``, or ``http://feeds.example.com`` if +you are using a CNAME on your own domain (i.e., FeedBurner's "MyBrand" feature). There are two fields to configure in the `FeedBurner `_ interface: "Original Feed" and "Feed Address". In this example, the "Original Feed" would be -`http://www.example.com/thymefeeds/main.xml` and the "Feed Address" suffix -would be `thymefeeds/main.xml`. +``http://www.example.com/thymefeeds/main.xml`` and the "Feed Address" suffix +would be ``thymefeeds/main.xml``. + Pagination ========== The default behaviour of Pelican is to list all the article titles along -with a short description on the index page. While it works pretty well -for small-to-medium blogs, for sites with large quantity of articles it would -be convenient to have a way to paginate the list. +with a short description on the index page. While this works well for +small-to-medium sites, sites with a large quantity of articles will probably +benefit from paginating this list. You can use the following settings to configure the pagination. ================================================ ===================================================== -Setting name (default value) What does it do? +Setting name (followed by default value, if any) What does it do? ================================================ ===================================================== -`DEFAULT_ORPHANS` (``0``) The minimum number of articles allowed on the - last page. Use this when you don't want to - have a last page with very few articles. -`DEFAULT_PAGINATION` (``False``) The maximum number of articles to include on a +``DEFAULT_ORPHANS = 0`` The minimum number of articles allowed on the + last page. Use this when you don't want the last page + to only contain a handful of articles. +``DEFAULT_PAGINATION = False`` The maximum number of articles to include on a page, not including orphans. False to disable pagination. +``PAGINATION_PATTERNS`` A set of patterns that are used to determine advanced + pagination output. ================================================ ===================================================== + +Using Pagination Patterns +------------------------- + +The ``PAGINATION_PATTERNS`` setting can be used to configure where +subsequent pages are created. The setting is a sequence of three +element tuples, where each tuple consists of:: + + (minimum page, URL setting, SAVE_AS setting,) + +For example, if you wanted the first page to just be ``/``, and the +second (and subsequent) pages to be ``/page/2/``, you would set +``PAGINATION_PATTERNS`` as follows:: + + PAGINATION_PATTERNS = ( + (1, '{base_name}/', '{base_name}/index.html'), + (2, '{base_name}/page/{number}/', '{base_name}/page/{number}/index.html'), + ) + +This would cause the first page to be written to +``{base_name}/index.html``, and subsequent ones would be written into +``page/{number}`` directories. + + Tag cloud ========= @@ -342,51 +627,76 @@ If you want to generate a tag cloud with all your tags, you can do so using the following settings. ================================================ ===================================================== -Setting name (default value) What does it do? +Setting name (followed by default value) What does it do? ================================================ ===================================================== -`TAG_CLOUD_STEPS` (``4``) Count of different font sizes in the tag +``TAG_CLOUD_STEPS = 4`` Count of different font sizes in the tag cloud. -`TAG_CLOUD_MAX_ITEMS` (``100``) Maximum number of tags in the cloud. +``TAG_CLOUD_MAX_ITEMS = 100`` Maximum number of tags in the cloud. ================================================ ===================================================== -The default theme does not support tag clouds, but it is pretty easy to add:: +The default theme does not include a tag cloud, but it is pretty easy to add one:: -
+ +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]> + + 175 + 2012-02-16 15:52:55 + 0000-00-00 00:00:00 + open + open + html-entity-test + publish + 0 + 0 + post + + 0 + + + _edit_last + + + + + Code in List + http://thisisa.test/?p=175 + Thu, 01 Jan 1970 00:00:00 +0000 + bob + http://thisisa.test/?p=175 + + +
  • List Item One!
  • +
  • List Item Two!
  • +
  • This is a code sample +
    +
    +  a = [1, 2, 3]
    +  b = [4, 5, 6]
    +  for i in zip(a, b):
    +    print i
    +
    +
  • +
  • List Item Four!
  • + + +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    + + 175 + 2012-02-16 15:52:55 + 0000-00-00 00:00:00 + open + open + code-in-list-test + publish + 0 + 0 + post + + 0 + + + _edit_last + + +
    + + A custom post in category 4 + http://thisisa.test/?p=175 + Thu, 01 Jan 1970 00:00:00 +0000 + bob + http://thisisa.test/?p=175 + + +
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • +
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • + + +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    + + 175 + 2012-02-16 15:52:55 + 0000-00-00 00:00:00 + open + open + custpost1cat4 + publish + 0 + 0 + custom1 + + 0 + + + _edit_last + + +
    + + A custom post in category 5 + http://thisisa.test/?p=176 + Thu, 01 Jan 1970 00:00:00 +0000 + bob + http://thisisa.test/?p=176 + + +
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • +
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • + + +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    + + 176 + 2012-02-16 15:52:55 + 0000-00-00 00:00:00 + open + open + custpost1cat5 + publish + 0 + 0 + custom1 + + 0 + + + _edit_last + + +
    + + A 2nd custom post type also in category 5 + http://thisisa.test/?p=177 + Thu, 01 Jan 1970 00:00:00 +0000 + bob + http://thisisa.test/?p=177 + + +
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • +
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  • + + +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]>
    + + 177 + 2012-02-16 15:52:55 + 0000-00-00 00:00:00 + open + open + custpost2cat5 + publish + 0 + 0 + custom2 + + 0 + + + _edit_last + + +
    + + Attachment with a parent + http://thisisa.test/?attachment_id=24 + Sat, 04 Feb 2012 03:17:33 +0000 + bob + http://thisurlisinvalid.notarealdomain/not_an_image.jpg + + + + 25 + 2012-02-04 03:17:33 + 2012-02-04 03:17:33 + open + open + attachment-with-a-parent + inherit + 8 + 0 + attachment + + 0 + http://thisurlisinvalid.notarealdomain/not_an_image.jpg + + _wp_attachment_metadata + + + + _wp_attached_file + + + + _wp_attachment_image_alt + + + + + 2nd Attachment to same parent + http://thisisa.test/?attachment_id=25 + Sat, 04 Feb 2012 03:17:33 +0000 + bob + http://en.wikipedia.org/wiki/File:Pelikan_Walvis_Bay.jpg + + + + 25 + 2012-02-04 03:17:33 + 2012-02-04 03:17:33 + open + open + 2nd[attachment-to-same-parent + inherit + 8 + 0 + attachment + + 0 + http://en.wikipedia.org/wiki/File:Pelikan_Walvis_Bay.jpg + + _wp_attachment_metadata + + + + _wp_attached_file + + + + _wp_attachment_image_alt + + + + + Attachment with a different parent + http://thisisa.test/?attachment_id=26 + Sat, 04 Feb 2012 03:17:33 +0000 + bob + http://thisurlisinvalid.notarealdomain + + + + 25 + 2012-02-04 03:17:33 + 2012-02-04 03:17:33 + open + open + attachment-with-a-different-parent + inherit + 25 + 0 + attachment + + 0 + http://thisurlisinvalid.notarealdomain + + _wp_attachment_metadata + + + + _wp_attached_file + + + + _wp_attachment_image_alt + + + + diff --git a/tests/default_conf.py b/pelican/tests/default_conf.py similarity index 70% rename from tests/default_conf.py rename to pelican/tests/default_conf.py index acb7d9da..62594894 100644 --- a/tests/default_conf.py +++ b/pelican/tests/default_conf.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- -AUTHOR = u'Alexis Métaireau' -SITENAME = u"Alexis' log" +from __future__ import unicode_literals, print_function +AUTHOR = 'Alexis Métaireau' +SITENAME = "Alexis' log" SITEURL = 'http://blog.notmyidea.org' TIMEZONE = 'UTC' @@ -8,7 +9,6 @@ GITHUB_URL = 'http://github.com/ametaireau/' DISQUS_SITENAME = "blog-notmyidea" PDF_GENERATOR = False REVERSE_CATEGORY_ORDER = True -LOCALE = "" DEFAULT_PAGINATION = 2 FEED_RSS = 'feeds/all.rss.xml' @@ -18,7 +18,7 @@ LINKS = (('Biologeek', 'http://biologeek.org'), ('Filyb', "http://filyb.info/"), ('Libert-fr', "http://www.libert-fr.com"), ('N1k0', "http://prendreuncafe.com/blog/"), - (u'Tarek Ziadé', "http://ziade.org/blog"), + ('Tarek Ziadé', "http://ziade.org/blog"), ('Zubin Mithra', "http://zubin71.wordpress.com/"),) SOCIAL = (('twitter', 'http://twitter.com/ametaireau'), @@ -28,11 +28,16 @@ SOCIAL = (('twitter', 'http://twitter.com/ametaireau'), # global metadata to all the contents DEFAULT_METADATA = (('yeah', 'it is'),) -# static paths will be copied under the same name -STATIC_PATHS = ["pictures",] +# path-specific metadata +EXTRA_PATH_METADATA = { + 'extra/robots.txt': {'path': 'robots.txt'}, + } -# A list of files to copy from the source to the destination -FILES_TO_COPY = (('extra/robots.txt', 'robots.txt'),) +# static paths will be copied without parsing their contents +STATIC_PATHS = [ + 'pictures', + 'extra/robots.txt', + ] # foobar will not be used, because it's not in caps. All configuration keys # have to be in caps diff --git a/pelican/plugins/__init__.py b/pelican/tests/mixed_content/fake_image.jpg similarity index 100% rename from pelican/plugins/__init__.py rename to pelican/tests/mixed_content/fake_image.jpg diff --git a/pelican/tests/mixed_content/short_page.md b/pelican/tests/mixed_content/short_page.md new file mode 100644 index 00000000..46ca45ac --- /dev/null +++ b/pelican/tests/mixed_content/short_page.md @@ -0,0 +1,3 @@ +Title: Short Page + +This is a page with little text. diff --git a/tests/__init__.py b/pelican/tests/mixed_content/subdir/subdir_fake_image.jpg similarity index 100% rename from tests/__init__.py rename to pelican/tests/mixed_content/subdir/subdir_fake_image.jpg diff --git a/pelican/tests/nested_content/maindir/maindir.md b/pelican/tests/nested_content/maindir/maindir.md new file mode 100644 index 00000000..443e1827 --- /dev/null +++ b/pelican/tests/nested_content/maindir/maindir.md @@ -0,0 +1,3 @@ +Title: Main Dir Page + +This page lives in maindir. diff --git a/pelican/tests/nested_content/maindir/subdir/subdir.md b/pelican/tests/nested_content/maindir/subdir/subdir.md new file mode 100644 index 00000000..32e73617 --- /dev/null +++ b/pelican/tests/nested_content/maindir/subdir/subdir.md @@ -0,0 +1,3 @@ +Title: Subdir Page + +This page lives in maindir/subdir. diff --git a/pelican/tests/output/basic/a-markdown-powered-article.html b/pelican/tests/output/basic/a-markdown-powered-article.html new file mode 100644 index 00000000..5fcc42a9 --- /dev/null +++ b/pelican/tests/output/basic/a-markdown-powered-article.html @@ -0,0 +1,69 @@ + + + + + A markdown powered article + + + + + + + + +
    + +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/archives.html b/pelican/tests/output/basic/archives.html new file mode 100644 index 00000000..f8f1a67f --- /dev/null +++ b/pelican/tests/output/basic/archives.html @@ -0,0 +1,72 @@ + + + + + A Pelican Blog + + + + + + + + +
    +

    Archives for A Pelican Blog

    + +
    +
    Fri 30 November 2012
    +
    FILENAME_METADATA example
    +
    Wed 29 February 2012
    +
    Second article
    +
    Wed 20 April 2011
    +
    A markdown powered article
    +
    Thu 17 February 2011
    +
    Article 1
    +
    Thu 17 February 2011
    +
    Article 2
    +
    Thu 17 February 2011
    +
    Article 3
    +
    Thu 02 December 2010
    +
    This is a super article !
    +
    Wed 20 October 2010
    +
    Oh yeah !
    +
    Fri 15 October 2010
    +
    Unbelievable !
    +
    Sun 14 March 2010
    +
    The baz tag
    +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/article-1.html b/pelican/tests/output/basic/article-1.html new file mode 100644 index 00000000..4ea7f4e3 --- /dev/null +++ b/pelican/tests/output/basic/article-1.html @@ -0,0 +1,68 @@ + + + + + Article 1 + + + + + + + + +
    +
    +
    +

    + Article 1

    +
    + +
    +
    + + Published: Thu 17 February 2011 + + +

    In cat1.

    + +

    Article 1

    + +
    + +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/article-2.html b/pelican/tests/output/basic/article-2.html new file mode 100644 index 00000000..45130e55 --- /dev/null +++ b/pelican/tests/output/basic/article-2.html @@ -0,0 +1,68 @@ + + + + + Article 2 + + + + + + + + +
    +
    +
    +

    + Article 2

    +
    + +
    +
    + + Published: Thu 17 February 2011 + + +

    In cat1.

    + +

    Article 2

    + +
    + +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/article-3.html b/pelican/tests/output/basic/article-3.html new file mode 100644 index 00000000..8603430f --- /dev/null +++ b/pelican/tests/output/basic/article-3.html @@ -0,0 +1,68 @@ + + + + + Article 3 + + + + + + + + +
    +
    +
    +

    + Article 3

    +
    + +
    +
    + + Published: Thu 17 February 2011 + + +

    In cat1.

    + +

    Article 3

    + +
    + +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/author/alexis-metaireau.html b/pelican/tests/output/basic/author/alexis-metaireau.html new file mode 100644 index 00000000..11d54185 --- /dev/null +++ b/pelican/tests/output/basic/author/alexis-metaireau.html @@ -0,0 +1,112 @@ + + + + + A Pelican Blog - Alexis Métaireau + + + + + + + + + + +
    +

    Other articles

    +
    +
      + +
    1. +
      +

      Oh yeah !

      +
      + +
      +
      +

      Why not ?

      +

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !

      +alternate text +
      + + read more +
      +
    2. +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/authors.html b/pelican/tests/output/basic/authors.html new file mode 100644 index 00000000..20df01d2 --- /dev/null +++ b/pelican/tests/output/basic/authors.html @@ -0,0 +1,54 @@ + + + + + A Pelican Blog - Authors + + + + + + + + + +
    +

    Authors on A Pelican Blog

    + +
    + +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/categories.html b/pelican/tests/output/basic/categories.html new file mode 100644 index 00000000..55e955c8 --- /dev/null +++ b/pelican/tests/output/basic/categories.html @@ -0,0 +1,52 @@ + + + + + A Pelican Blog + + + + + + + + + +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/category/bar.html b/pelican/tests/output/basic/category/bar.html new file mode 100644 index 00000000..18e434cb --- /dev/null +++ b/pelican/tests/output/basic/category/bar.html @@ -0,0 +1,68 @@ + + + + + A Pelican Blog - bar + + + + + + + + + + +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/category/cat1.html b/pelican/tests/output/basic/category/cat1.html new file mode 100644 index 00000000..f99eb497 --- /dev/null +++ b/pelican/tests/output/basic/category/cat1.html @@ -0,0 +1,127 @@ + + + + + A Pelican Blog - cat1 + + + + + + + + + + +
    +

    Other articles

    +
    +
      + +
    1. + +
    2. + +
    3. +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/category/misc.html b/pelican/tests/output/basic/category/misc.html new file mode 100644 index 00000000..fc724edb --- /dev/null +++ b/pelican/tests/output/basic/category/misc.html @@ -0,0 +1,138 @@ + + + + + A Pelican Blog - misc + + + + + + + + + + +
    +

    Other articles

    +
    +
      + +
    1. + +
    2. + +
    3. +
      +

      The baz tag

      +
      + +
      +
      + + Published: Sun 14 March 2010 + + +

      In misc.

      + +

      This article overrides the listening of the articles under the baz tag.

      + + read more +
      +
    4. +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/category/yeah.html b/pelican/tests/output/basic/category/yeah.html new file mode 100644 index 00000000..7fe75a86 --- /dev/null +++ b/pelican/tests/output/basic/category/yeah.html @@ -0,0 +1,78 @@ + + + + + A Pelican Blog - yeah + + + + + + + + + + +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/feeds/alexis-metaireau.atom.xml b/pelican/tests/output/basic/feeds/alexis-metaireau.atom.xml new file mode 100644 index 00000000..f9a2e6e1 --- /dev/null +++ b/pelican/tests/output/basic/feeds/alexis-metaireau.atom.xml @@ -0,0 +1,20 @@ + +A Pelican Blog/2013-11-17T23:29:00+00:00This is a super article !2013-11-17T23:29:00+00:00Alexis Métaireautag:,2010-12-02:this-is-a-super-article.html<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Oh yeah !2010-10-20T10:14:00+00:00Alexis Métaireautag:,2010-10-20:oh-yeah.html<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> + diff --git a/pelican/tests/output/basic/feeds/alexis-metaireau.rss.xml b/pelican/tests/output/basic/feeds/alexis-metaireau.rss.xml new file mode 100644 index 00000000..511ffa0e --- /dev/null +++ b/pelican/tests/output/basic/feeds/alexis-metaireau.rss.xml @@ -0,0 +1,20 @@ + +A Pelican Blog/Sun, 17 Nov 2013 23:29:00 +0000This is a super article !/this-is-a-super-article.html<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Alexis MétaireauSun, 17 Nov 2013 23:29:00 +0000tag:,2010-12-02:this-is-a-super-article.htmlfoobarfoobarOh yeah !/oh-yeah.html<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0000tag:,2010-10-20:oh-yeah.htmlohbaryeah diff --git a/pelican/tests/output/basic/feeds/all-en.atom.xml b/pelican/tests/output/basic/feeds/all-en.atom.xml new file mode 100644 index 00000000..3ce41d77 --- /dev/null +++ b/pelican/tests/output/basic/feeds/all-en.atom.xml @@ -0,0 +1,61 @@ + +A Pelican Blog/2013-11-17T23:29:00+00:00FILENAME_METADATA example2012-11-30T00:00:00+00:00tag:,2012-11-30:filename_metadata-example.html<p>Some cool stuff!</p> +Second article2012-02-29T00:00:00+00:00tag:,2012-02-29:second-article.html<p>This is some article, in english</p> +A markdown powered article2011-04-20T00:00:00+00:00tag:,2011-04-20:a-markdown-powered-article.html<p>You're mutually oblivious.</p> +<p><a href="/unbelievable.html">a root-relative link to unbelievable</a> +<a href="/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+00:00tag:,2011-02-17:article-1.html<p>Article 1</p> +Article 22011-02-17T00:00:00+00:00tag:,2011-02-17:article-2.html<p>Article 2</p> +Article 32011-02-17T00:00:00+00:00tag:,2011-02-17:article-3.html<p>Article 3</p> +This is a super article !2013-11-17T23:29:00+00:00Alexis Métaireautag:,2010-12-02:this-is-a-super-article.html<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Oh yeah !2010-10-20T10:14:00+00:00Alexis Métaireautag:,2010-10-20:oh-yeah.html<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Unbelievable !2010-10-15T20:30:00+00:00tag:,2010-10-15:unbelievable.html<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> +<a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +The baz tag2010-03-14T00:00:00+00:00tag:,2010-03-14:tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> + diff --git a/pelican/tests/output/basic/feeds/all-fr.atom.xml b/pelican/tests/output/basic/feeds/all-fr.atom.xml new file mode 100644 index 00000000..54056df6 --- /dev/null +++ b/pelican/tests/output/basic/feeds/all-fr.atom.xml @@ -0,0 +1,3 @@ + +A Pelican Blog/2012-02-29T00:00:00+00:00Deuxième article2012-02-29T00:00:00+00:00tag:,2012-02-29:second-article-fr.html<p>Ceci est un article, en français.</p> + diff --git a/pelican/tests/output/basic/feeds/all.atom.xml b/pelican/tests/output/basic/feeds/all.atom.xml new file mode 100644 index 00000000..3a9478a4 --- /dev/null +++ b/pelican/tests/output/basic/feeds/all.atom.xml @@ -0,0 +1,62 @@ + +A Pelican Blog/2013-11-17T23:29:00+00:00FILENAME_METADATA example2012-11-30T00:00:00+00:00tag:,2012-11-30:filename_metadata-example.html<p>Some cool stuff!</p> +Second article2012-02-29T00:00:00+00:00tag:,2012-02-29:second-article.html<p>This is some article, in english</p> +Deuxième article2012-02-29T00:00:00+00:00tag:,2012-02-29:second-article-fr.html<p>Ceci est un article, en français.</p> +A markdown powered article2011-04-20T00:00:00+00:00tag:,2011-04-20:a-markdown-powered-article.html<p>You're mutually oblivious.</p> +<p><a href="/unbelievable.html">a root-relative link to unbelievable</a> +<a href="/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+00:00tag:,2011-02-17:article-1.html<p>Article 1</p> +Article 22011-02-17T00:00:00+00:00tag:,2011-02-17:article-2.html<p>Article 2</p> +Article 32011-02-17T00:00:00+00:00tag:,2011-02-17:article-3.html<p>Article 3</p> +This is a super article !2013-11-17T23:29:00+00:00Alexis Métaireautag:,2010-12-02:this-is-a-super-article.html<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Oh yeah !2010-10-20T10:14:00+00:00Alexis Métaireautag:,2010-10-20:oh-yeah.html<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Unbelievable !2010-10-15T20:30:00+00:00tag:,2010-10-15:unbelievable.html<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> +<a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +The baz tag2010-03-14T00:00:00+00:00tag:,2010-03-14:tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> + diff --git a/tests/output/basic/feeds/bar.atom.xml b/pelican/tests/output/basic/feeds/bar.atom.xml similarity index 50% rename from tests/output/basic/feeds/bar.atom.xml rename to pelican/tests/output/basic/feeds/bar.atom.xml index 7b842a63..d1c678ae 100644 --- a/tests/output/basic/feeds/bar.atom.xml +++ b/pelican/tests/output/basic/feeds/bar.atom.xml @@ -1,8 +1,8 @@ -A Pelican Blog/2010-10-20T10:14:00ZOh yeah !2010-10-20T10:14:00ZAlexis Métaireautag:,2010-10-20:oh-yeah.html<div class="section" id="why-not"> +A Pelican Blog/2010-10-20T10:14:00+00:00Oh yeah !2010-10-20T10:14:00+00:00Alexis Métaireautag:,2010-10-20:oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> -<img alt="alternate text" src="pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> - \ No newline at end of file + diff --git a/pelican/tests/output/basic/feeds/cat1.atom.xml b/pelican/tests/output/basic/feeds/cat1.atom.xml new file mode 100644 index 00000000..a3c35956 --- /dev/null +++ b/pelican/tests/output/basic/feeds/cat1.atom.xml @@ -0,0 +1,7 @@ + +A Pelican Blog/2011-04-20T00:00:00+00:00A markdown powered article2011-04-20T00:00:00+00:00tag:,2011-04-20:a-markdown-powered-article.html<p>You're mutually oblivious.</p> +<p><a href="/unbelievable.html">a root-relative link to unbelievable</a> +<a href="/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+00:00tag:,2011-02-17:article-1.html<p>Article 1</p> +Article 22011-02-17T00:00:00+00:00tag:,2011-02-17:article-2.html<p>Article 2</p> +Article 32011-02-17T00:00:00+00:00tag:,2011-02-17:article-3.html<p>Article 3</p> + diff --git a/pelican/tests/output/basic/feeds/misc.atom.xml b/pelican/tests/output/basic/feeds/misc.atom.xml new file mode 100644 index 00000000..a9b5977b --- /dev/null +++ b/pelican/tests/output/basic/feeds/misc.atom.xml @@ -0,0 +1,38 @@ + +A Pelican Blog/2012-11-30T00:00:00+00:00FILENAME_METADATA example2012-11-30T00:00:00+00:00tag:,2012-11-30:filename_metadata-example.html<p>Some cool stuff!</p> +Second article2012-02-29T00:00:00+00:00tag:,2012-02-29:second-article.html<p>This is some article, in english</p> +Unbelievable !2010-10-15T20:30:00+00:00tag:,2010-10-15:unbelievable.html<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="/a-markdown-powered-article.html">a root-relative link to markdown-article</a> +<a class="reference external" href="/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +The baz tag2010-03-14T00:00:00+00:00tag:,2010-03-14:tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> + diff --git a/tests/output/basic/feeds/yeah.atom.xml b/pelican/tests/output/basic/feeds/yeah.atom.xml similarity index 50% rename from tests/output/basic/feeds/yeah.atom.xml rename to pelican/tests/output/basic/feeds/yeah.atom.xml index fabeb52f..0df396a2 100644 --- a/tests/output/basic/feeds/yeah.atom.xml +++ b/pelican/tests/output/basic/feeds/yeah.atom.xml @@ -1,14 +1,14 @@ -A Pelican Blog/2010-12-02T10:14:00ZThis is a super article !2010-12-02T10:14:00ZAlexis Métaireautag:,2010-12-02:this-is-a-super-article.html<p>Some content here !</p> +A Pelican Blog/2013-11-17T23:29:00+00:00This is a super article !2013-11-17T23:29:00+00:00Alexis Métaireautag:,2010-12-02:this-is-a-super-article.html<p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> - \ No newline at end of file + diff --git a/pelican/tests/output/basic/filename_metadata-example.html b/pelican/tests/output/basic/filename_metadata-example.html new file mode 100644 index 00000000..638c65dd --- /dev/null +++ b/pelican/tests/output/basic/filename_metadata-example.html @@ -0,0 +1,68 @@ + + + + + FILENAME_METADATA example + + + + + + + + +
    + +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/index.html b/pelican/tests/output/basic/index.html new file mode 100644 index 00000000..f3814b00 --- /dev/null +++ b/pelican/tests/output/basic/index.html @@ -0,0 +1,275 @@ + + + + + A Pelican Blog + + + + + + + + + + +
    +

    Other articles

    +
    +
      + +
    1. + +
    2. + +
    3. + +
    4. + +
    5. + +
    6. + +
    7. +
      +

      Oh yeah !

      +
      + +
      +
      +

      Why not ?

      +

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !

      +alternate text +
      + + read more +
      +
    8. + +
    9. + +
    10. +
      +

      The baz tag

      +
      + +
      +
      + + Published: Sun 14 March 2010 + + +

      In misc.

      + +

      This article overrides the listening of the articles under the baz tag.

      + + read more +
      +
    11. +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/oh-yeah.html b/pelican/tests/output/basic/oh-yeah.html new file mode 100644 index 00000000..76be69fe --- /dev/null +++ b/pelican/tests/output/basic/oh-yeah.html @@ -0,0 +1,76 @@ + + + + + Oh yeah ! + + + + + + + + +
    +
    +
    +

    + Oh yeah !

    +
    + +
    +
    +

    Why not ?

    +

    After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !

    +alternate text +
    + +
    + +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/override/index.html b/pelican/tests/output/basic/override/index.html new file mode 100644 index 00000000..ed9fa92a --- /dev/null +++ b/pelican/tests/output/basic/override/index.html @@ -0,0 +1,53 @@ + + + + + Override url/save_as + + + + + + + + +
    +

    Override url/save_as

    + +

    Test page which overrides save_as and url so that this page will be generated +at a custom location.

    + +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/pages/this-is-a-test-hidden-page.html b/pelican/tests/output/basic/pages/this-is-a-test-hidden-page.html new file mode 100644 index 00000000..ac31987a --- /dev/null +++ b/pelican/tests/output/basic/pages/this-is-a-test-hidden-page.html @@ -0,0 +1,53 @@ + + + + + This is a test hidden page + + + + + + + + +
    +

    This is a test hidden page

    + +

    This is great for things like error(404) pages +Anyone can see this page but it's not linked to anywhere!

    + +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/pages/this-is-a-test-page.html b/pelican/tests/output/basic/pages/this-is-a-test-page.html new file mode 100644 index 00000000..43e5f72e --- /dev/null +++ b/pelican/tests/output/basic/pages/this-is-a-test-page.html @@ -0,0 +1,53 @@ + + + + + This is a test page + + + + + + + + +
    +

    This is a test page

    + +

    Just an image.

    +alternate text + +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/second-article-fr.html b/pelican/tests/output/basic/second-article-fr.html new file mode 100644 index 00000000..551027da --- /dev/null +++ b/pelican/tests/output/basic/second-article-fr.html @@ -0,0 +1,70 @@ + + + + + Deuxième article + + + + + + + + +
    +
    +
    +

    + Deuxième article

    +
    + +
    +
    + + Published: Wed 29 February 2012 + + +

    In misc.

    +

    tags: foobarbaz

    Translations: + en + +

    Ceci est un article, en français.

    + +
    + +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/second-article.html b/pelican/tests/output/basic/second-article.html new file mode 100644 index 00000000..ed350752 --- /dev/null +++ b/pelican/tests/output/basic/second-article.html @@ -0,0 +1,70 @@ + + + + + Second article + + + + + + + + +
    +
    +
    +

    + Second article

    +
    + +
    +
    + + Published: Wed 29 February 2012 + + +

    In misc.

    +

    tags: foobarbaz

    Translations: + fr + +

    This is some article, in english

    + +
    + +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/tag/bar.html b/pelican/tests/output/basic/tag/bar.html new file mode 100644 index 00000000..5331767b --- /dev/null +++ b/pelican/tests/output/basic/tag/bar.html @@ -0,0 +1,124 @@ + + + + + A Pelican Blog - bar + + + + + + + + + + +
    +

    Other articles

    +
    +
      + +
    1. + +
    2. +
      +

      Oh yeah !

      +
      + +
      +
      +

      Why not ?

      +

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !

      +alternate text +
      + + read more +
      +
    3. +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/tag/baz.html b/pelican/tests/output/basic/tag/baz.html new file mode 100644 index 00000000..dc26d8e1 --- /dev/null +++ b/pelican/tests/output/basic/tag/baz.html @@ -0,0 +1,68 @@ + + + + + The baz tag + + + + + + + + +
    +
    +
    +

    + The baz tag

    +
    + +
    +
    + + Published: Sun 14 March 2010 + + +

    In misc.

    + +

    This article overrides the listening of the articles under the baz tag.

    + +
    + +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/tag/foo.html b/pelican/tests/output/basic/tag/foo.html new file mode 100644 index 00000000..aed3ad17 --- /dev/null +++ b/pelican/tests/output/basic/tag/foo.html @@ -0,0 +1,96 @@ + + + + + A Pelican Blog - foo + + + + + + + + + + +
    +

    Other articles

    +
    +
      + +
    1. +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/tag/foobar.html b/pelican/tests/output/basic/tag/foobar.html new file mode 100644 index 00000000..540cde25 --- /dev/null +++ b/pelican/tests/output/basic/tag/foobar.html @@ -0,0 +1,78 @@ + + + + + A Pelican Blog - foobar + + + + + + + + + + +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/tag/oh.html b/pelican/tests/output/basic/tag/oh.html new file mode 100644 index 00000000..ef876b8d --- /dev/null +++ b/pelican/tests/output/basic/tag/oh.html @@ -0,0 +1,52 @@ + + + + + Oh Oh Oh + + + + + + + + +
    +

    Oh Oh Oh

    + +

    This page overrides the listening of the articles under the oh tag.

    + +
    +
    + +
    + + + + + \ No newline at end of file diff --git a/pelican/tests/output/basic/tag/yeah.html b/pelican/tests/output/basic/tag/yeah.html new file mode 100644 index 00000000..b8da2bc6 --- /dev/null +++ b/pelican/tests/output/basic/tag/yeah.html @@ -0,0 +1,68 @@ + + + + + A Pelican Blog - yeah + + + + + + + + + + +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/tags.html b/pelican/tests/output/basic/tags.html new file mode 100644 index 00000000..0eda47d7 --- /dev/null +++ b/pelican/tests/output/basic/tags.html @@ -0,0 +1,59 @@ + + + + + A Pelican Blog - Tags + + + + + + + + + +
    +

    Tags for A Pelican Blog

    + +
    + +
    + +
    + + + + + diff --git a/tests/output/custom/theme/css/main.css b/pelican/tests/output/basic/theme/css/main.css similarity index 84% rename from tests/output/custom/theme/css/main.css rename to pelican/tests/output/basic/theme/css/main.css index 3d94200b..2efb518d 100644 --- a/tests/output/custom/theme/css/main.css +++ b/pelican/tests/output/basic/theme/css/main.css @@ -3,15 +3,16 @@ Date: July 2009 Description: Sample layout for HTML5 and CSS3 goodness. Version: 1.0 - Author: Enrique Ramírez - Autor URI: http://enrique-ramirez.com + License: MIT + Licensed by: Smashing Media GmbH + Original author: Enrique Ramírez */ /* Imports */ @import url("reset.css"); @import url("pygment.css"); @import url("typogrify.css"); -@import url(http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz&subset=latin); +@import url(//fonts.googleapis.com/css?family=Yanone+Kaffeesatz&subset=latin); /***** Global *****/ /* Body */ @@ -65,7 +66,9 @@ h1 a:hover { } /* Paragraphs */ -p {margin-bottom: 1.143em;} +div.line-block, +p { margin-top: 1em; + margin-bottom: 1em;} strong, b {font-weight: bold;} em, i {font-style: italic;} @@ -73,14 +76,16 @@ em, i {font-style: italic;} /* Lists */ ul { list-style: outside disc; - margin: 1em 0 1.5em 1.5em; + margin: 0em 0 0 1.5em; } ol { list-style: outside decimal; - margin: 1em 0 1.5em 1.5em; + margin: 0em 0 0 1.5em; } +li { margin-top: 0.5em;} + .post-info { float:right; margin:10px; @@ -88,6 +93,7 @@ ol { } .post-info p{ + margin-top: 1px; margin-bottom: 1px; } @@ -301,15 +307,32 @@ img.left, figure.left {float: left; margin: 0 2em 2em 0;} } /* Icons */ + .social a[href*='about.me'] {background-image: url('../images/icons/aboutme.png');} + .social a[href*='bitbucket.org'] {background-image: url('../images/icons/bitbucket.png');} .social a[href*='delicious.com'] {background-image: url('../images/icons/delicious.png');} .social a[href*='digg.com'] {background-image: url('../images/icons/digg.png');} .social a[href*='facebook.com'] {background-image: url('../images/icons/facebook.png');} - .social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');} - .social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('../images/icons/rss.png');} - .social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');} - .social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');} .social a[href*='gitorious.org'] {background-image: url('../images/icons/gitorious.png');} - .social a[href*='gittip.com'] {background-image: url('../images/icons/gittip.png');} + .social a[href*='github.com'], + .social a[href*='git.io'] { + background-image: url('../images/icons/github.png'); + background-size: 16px 16px; + } + .social a[href*='gittip.com'] {background-image: url('../images/icons/gittip.png');} + .social a[href*='plus.google.com'] {background-image: url('../images/icons/google-plus.png');} + .social a[href*='groups.google.com'] {background-image: url('../images/icons/google-groups.png');} + .social a[href*='news.ycombinator.com'], + .social a[href*='hackernewsers.com'] {background-image: url('../images/icons/hackernews.png');} + .social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');} + .social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');} + .social a[href*='reddit.com'] {background-image: url('../images/icons/reddit.png');} + .social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('../images/icons/rss.png');} + .social a[href*='slideshare.net'] {background-image: url('../images/icons/slideshare.png');} + .social a[href*='speakerdeck.com'] {background-image: url('../images/icons/speakerdeck.png');} + .social a[href*='stackoverflow.com'] {background-image: url('../images/icons/stackoverflow.png');} + .social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');} + .social a[href*='vimeo.com'] {background-image: url('../images/icons/vimeo.png');} + .social a[href*='youtube.com'] {background-image: url('../images/icons/youtube.png');} /* About diff --git a/tests/output/basic/theme/css/pygment.css b/pelican/tests/output/basic/theme/css/pygment.css similarity index 100% rename from tests/output/basic/theme/css/pygment.css rename to pelican/tests/output/basic/theme/css/pygment.css diff --git a/tests/output/basic/theme/css/reset.css b/pelican/tests/output/basic/theme/css/reset.css similarity index 100% rename from tests/output/basic/theme/css/reset.css rename to pelican/tests/output/basic/theme/css/reset.css diff --git a/tests/output/basic/theme/css/typogrify.css b/pelican/tests/output/basic/theme/css/typogrify.css similarity index 100% rename from tests/output/basic/theme/css/typogrify.css rename to pelican/tests/output/basic/theme/css/typogrify.css diff --git a/tests/output/basic/theme/css/wide.css b/pelican/tests/output/basic/theme/css/wide.css similarity index 100% rename from tests/output/basic/theme/css/wide.css rename to pelican/tests/output/basic/theme/css/wide.css diff --git a/pelican/tests/output/basic/theme/images/icons/aboutme.png b/pelican/tests/output/basic/theme/images/icons/aboutme.png new file mode 100644 index 00000000..9609df3b Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/aboutme.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/bitbucket.png b/pelican/tests/output/basic/theme/images/icons/bitbucket.png new file mode 100644 index 00000000..d05ba161 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/bitbucket.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/delicious.png b/pelican/tests/output/basic/theme/images/icons/delicious.png new file mode 100644 index 00000000..3dccdd84 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/delicious.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/facebook.png b/pelican/tests/output/basic/theme/images/icons/facebook.png new file mode 100644 index 00000000..74e7ad52 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/facebook.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/github.png b/pelican/tests/output/basic/theme/images/icons/github.png new file mode 100644 index 00000000..8b25551a Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/github.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/gitorious.png b/pelican/tests/output/basic/theme/images/icons/gitorious.png new file mode 100644 index 00000000..3eeb3ece Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/gitorious.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/gittip.png b/pelican/tests/output/basic/theme/images/icons/gittip.png new file mode 100644 index 00000000..af949625 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/gittip.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/google-groups.png b/pelican/tests/output/basic/theme/images/icons/google-groups.png new file mode 100644 index 00000000..5de15e68 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/google-groups.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/google-plus.png b/pelican/tests/output/basic/theme/images/icons/google-plus.png new file mode 100644 index 00000000..3c6b7432 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/google-plus.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/hackernews.png b/pelican/tests/output/basic/theme/images/icons/hackernews.png new file mode 100644 index 00000000..fc7a82d4 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/hackernews.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/lastfm.png b/pelican/tests/output/basic/theme/images/icons/lastfm.png new file mode 100644 index 00000000..3a6c6262 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/lastfm.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/linkedin.png b/pelican/tests/output/basic/theme/images/icons/linkedin.png new file mode 100644 index 00000000..d29c1201 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/linkedin.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/reddit.png b/pelican/tests/output/basic/theme/images/icons/reddit.png new file mode 100644 index 00000000..71ae1215 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/reddit.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/rss.png b/pelican/tests/output/basic/theme/images/icons/rss.png new file mode 100644 index 00000000..7862c65a Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/rss.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/slideshare.png b/pelican/tests/output/basic/theme/images/icons/slideshare.png new file mode 100644 index 00000000..ecc97410 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/slideshare.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/speakerdeck.png b/pelican/tests/output/basic/theme/images/icons/speakerdeck.png new file mode 100644 index 00000000..087d0931 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/speakerdeck.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/stackoverflow.png b/pelican/tests/output/basic/theme/images/icons/stackoverflow.png new file mode 100644 index 00000000..f5b65e99 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/stackoverflow.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/twitter.png b/pelican/tests/output/basic/theme/images/icons/twitter.png new file mode 100644 index 00000000..d0ef3cc1 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/twitter.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/vimeo.png b/pelican/tests/output/basic/theme/images/icons/vimeo.png new file mode 100644 index 00000000..dba47202 Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/vimeo.png differ diff --git a/pelican/tests/output/basic/theme/images/icons/youtube.png b/pelican/tests/output/basic/theme/images/icons/youtube.png new file mode 100644 index 00000000..ce6cbe4f Binary files /dev/null and b/pelican/tests/output/basic/theme/images/icons/youtube.png differ diff --git a/pelican/tests/output/basic/this-is-a-super-article.html b/pelican/tests/output/basic/this-is-a-super-article.html new file mode 100644 index 00000000..cf957ebf --- /dev/null +++ b/pelican/tests/output/basic/this-is-a-super-article.html @@ -0,0 +1,86 @@ + + + + + This is a super article ! + + + + + + + + +
    +
    +
    +

    + This is a super article !

    +
    + +
    +

    Some content here !

    +
    +

    This is a simple title

    +

    And here comes the cool stuff.

    +alternate text +alternate text +
    +>>> from ipdb import set_trace
    +>>> set_trace()
    +
    +

    → And now try with some utf8 hell: ééé

    +
    + +
    + +
    +
    +
    + +
    + + + + + diff --git a/pelican/tests/output/basic/unbelievable.html b/pelican/tests/output/basic/unbelievable.html new file mode 100644 index 00000000..b9b52031 --- /dev/null +++ b/pelican/tests/output/basic/unbelievable.html @@ -0,0 +1,100 @@ + + + + + Unbelievable ! + + + + + + + + +
    +
    +
    +

    + Unbelievable !

    +
    + +
    +
    + + Published: Fri 15 October 2010 + + +

    In misc.

    + +

    Or completely awesome. Depends the needs.

    +

    a root-relative link to markdown-article +a file-relative link to markdown-article

    +
    +

    Testing sourcecode directive

    +
    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    +
    +
    +
    +

    Testing another case

    +

    This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.

    +
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    +
    +

    Lovely.

    +
    +
    +

    Testing more sourcecode directives

    +
     8 def run(self):
    self.assert_has_content()
    10 try:
    lexer = get_lexer_by_name(self.arguments[0])
    12 except ValueError:
    # no lexer found - use the text one instead of an exception
    14 lexer = TextLexer()

    16 if ('linenos' in self.options and
    self.options['linenos'] not in ('table', 'inline')):
    18 self.options['linenos'] = 'table'

    20 for flag in ('nowrap', 'nobackground', 'anchorlinenos'):
    if flag in self.options:
    22 self.options[flag] = True

    24 # noclasses should already default to False, but just in case...
    formatter = HtmlFormatter(noclasses=False, **self.options)
    26 parsed = highlight('\n'.join(self.content), lexer, formatter)
    return [nodes.raw('', parsed, format='html')]
    +

    Lovely.

    +
    +
    +

    Testing even more sourcecode directives

    +formatter = self.options and VARIANTS[self.options.keys()[0]] +

    Lovely.

    +
    +
    +

    Testing overriding config defaults

    +

    Even if the default is line numbers, we can override it here

    +
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    +
    +

    Lovely.

    +
    + +
    + +
    +
    +
    + +
    + + + + + diff --git a/tests/output/custom/a-markdown-powered-article.html b/pelican/tests/output/custom/a-markdown-powered-article.html similarity index 69% rename from tests/output/custom/a-markdown-powered-article.html rename to pelican/tests/output/custom/a-markdown-powered-article.html index 9ca4763c..577d61b8 100644 --- a/tests/output/custom/a-markdown-powered-article.html +++ b/pelican/tests/output/custom/a-markdown-powered-article.html @@ -1,142 +1,97 @@ - A markdown powered article - - + A markdown powered article + - - - - - - - - + + - - Fork me on GitHub - - -

    - A markdown powered article

    -
    -
    - - Wed 20 April 2011 + -

    You're mutually oblivious.

    +

    You're mutually oblivious.

    +

    a root-relative link to unbelievable +a file-relative link to unbelievable

    -

    Comments !

    +
    -
    -
    - - - -
    - - - - - \ No newline at end of file + diff --git a/tests/output/custom/archives.html b/pelican/tests/output/custom/archives.html similarity index 73% rename from tests/output/custom/archives.html rename to pelican/tests/output/custom/archives.html index fe2ad2c4..13c3d980 100644 --- a/tests/output/custom/archives.html +++ b/pelican/tests/output/custom/archives.html @@ -1,129 +1,82 @@ - Alexis' log - - + Alexis' log + - - - - - - - - + + - - Fork me on GitHub - - -

    Archives for Alexis' log

    - +
    Fri 30 November 2012
    +
    FILENAME_METADATA example
    Wed 29 February 2012
    Second article
    -
    Wed 20 April 2011
    A markdown powered article
    -
    Thu 17 February 2011
    Article 1
    -
    Thu 17 February 2011
    Article 2
    -
    Thu 17 February 2011
    Article 3
    -
    Thu 02 December 2010
    This is a super article !
    -
    Wed 20 October 2010
    Oh yeah !
    -
    Fri 15 October 2010
    Unbelievable !
    - +
    Sun 14 March 2010
    +
    The baz tag
    -
    - - - -
    - - - - \ No newline at end of file diff --git a/tests/output/custom/article-1.html b/pelican/tests/output/custom/article-1.html similarity index 69% rename from tests/output/custom/article-1.html rename to pelican/tests/output/custom/article-1.html index b0e0f879..dea09247 100644 --- a/tests/output/custom/article-1.html +++ b/pelican/tests/output/custom/article-1.html @@ -1,143 +1,96 @@ - Article 1 - - + Article 1 + - - - - - - - - + + - - Fork me on GitHub - - -

    - Article 1

    -
    -
    - - Thu 17 February 2011 + -

    Article 1

    +

    Article 1

    -

    Comments !

    +
    -
    -
    - - - -
    - - - - - \ No newline at end of file + diff --git a/tests/output/custom/article-2.html b/pelican/tests/output/custom/article-2.html similarity index 69% rename from tests/output/custom/article-2.html rename to pelican/tests/output/custom/article-2.html index 973b870a..8d8ad1b3 100644 --- a/tests/output/custom/article-2.html +++ b/pelican/tests/output/custom/article-2.html @@ -1,143 +1,96 @@ - Article 2 - - + Article 2 + - - - - - - - - + + - - Fork me on GitHub - - -

    - Article 2

    -
    -
    - - Thu 17 February 2011 + -

    Article 2

    +

    Article 2

    -

    Comments !

    +
    -
    -
    - - - -
    - - - - - \ No newline at end of file + diff --git a/tests/output/custom/article-3.html b/pelican/tests/output/custom/article-3.html similarity index 69% rename from tests/output/custom/article-3.html rename to pelican/tests/output/custom/article-3.html index 7697a4ef..7539e0f9 100644 --- a/tests/output/custom/article-3.html +++ b/pelican/tests/output/custom/article-3.html @@ -1,143 +1,96 @@ - Article 3 - - + Article 3 + - - - - - - - - + + - - Fork me on GitHub - - -

    - Article 3

    -
    -
    - - Thu 17 February 2011 + -

    Article 3

    +

    Article 3

    -

    Comments !

    +
    -
    -
    - - - -
    - - - - - \ No newline at end of file + diff --git a/pelican/tests/output/custom/author/alexis-metaireau.html b/pelican/tests/output/custom/author/alexis-metaireau.html new file mode 100644 index 00000000..cb6d93a9 --- /dev/null +++ b/pelican/tests/output/custom/author/alexis-metaireau.html @@ -0,0 +1,173 @@ + + + + + Alexis' log - Alexis Métaireau + + + + + + + + + +Fork me on GitHub + + + + +
    +

    Other articles

    +
    +
      + +
    1. + +
    2. + +
    3. +
    +

    + Page 1 / 3 + » +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/pelican/tests/output/custom/author/alexis-metaireau2.html b/pelican/tests/output/custom/author/alexis-metaireau2.html new file mode 100644 index 00000000..abf5bdbb --- /dev/null +++ b/pelican/tests/output/custom/author/alexis-metaireau2.html @@ -0,0 +1,187 @@ + + + + + Alexis' log - Alexis Métaireau + + + + + + + + + +Fork me on GitHub + + + +
    +
      +
    1. + +
    2. + +
    3. + +
    4. +
      +

      Oh yeah !

      +
      + +
      +
      +

      Why not ?

      +

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !

      +alternate text +
      + + read more +

      There are comments.

      +
    5. +
    +

    + « + Page 2 / 3 + » +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/pelican/tests/output/custom/author/alexis-metaireau3.html b/pelican/tests/output/custom/author/alexis-metaireau3.html new file mode 100644 index 00000000..30aa3eff --- /dev/null +++ b/pelican/tests/output/custom/author/alexis-metaireau3.html @@ -0,0 +1,138 @@ + + + + + Alexis' log - Alexis Métaireau + + + + + + + + + +Fork me on GitHub + + + +
    +
      +
    1. + +
    2. +
    +

    + « + Page 3 / 3 +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom/authors.html b/pelican/tests/output/custom/authors.html new file mode 100644 index 00000000..d9aaef34 --- /dev/null +++ b/pelican/tests/output/custom/authors.html @@ -0,0 +1,82 @@ + + + + + Alexis' log - Authors + + + + + + + + + +Fork me on GitHub + + + +
    +

    Authors on Alexis' log

    + +
    + +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/tests/output/custom/categories.html b/pelican/tests/output/custom/categories.html similarity index 69% rename from tests/output/custom/categories.html rename to pelican/tests/output/custom/categories.html index bad9dcfd..17d9de76 100644 --- a/tests/output/custom/categories.html +++ b/pelican/tests/output/custom/categories.html @@ -1,109 +1,62 @@ - Alexis' log - - + Alexis' log + - - - - - - - - + + - - Fork me on GitHub - - - -
    - - - -
    - - - - \ No newline at end of file diff --git a/pelican/tests/output/custom/category/bar.html b/pelican/tests/output/custom/category/bar.html new file mode 100644 index 00000000..9ab46a2e --- /dev/null +++ b/pelican/tests/output/custom/category/bar.html @@ -0,0 +1,101 @@ + + + + + Alexis' log - bar + + + + + + + + + +Fork me on GitHub + + + + +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/pelican/tests/output/custom/category/cat1.html b/pelican/tests/output/custom/category/cat1.html new file mode 100644 index 00000000..76075edf --- /dev/null +++ b/pelican/tests/output/custom/category/cat1.html @@ -0,0 +1,170 @@ + + + + + Alexis' log - cat1 + + + + + + + + + +Fork me on GitHub + + + + +
    +

    Other articles

    +
    +
      + +
    1. + +
    2. + +
    3. +
    +

    + Page 1 / 1 +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom/category/misc.html b/pelican/tests/output/custom/category/misc.html new file mode 100644 index 00000000..3a470b7e --- /dev/null +++ b/pelican/tests/output/custom/category/misc.html @@ -0,0 +1,181 @@ + + + + + Alexis' log - misc + + + + + + + + + +Fork me on GitHub + + + + +
    +

    Other articles

    +
    +
      + +
    1. + +
    2. + +
    3. +
    +

    + Page 1 / 1 +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/tests/output/custom/category/yeah.html b/pelican/tests/output/custom/category/yeah.html similarity index 57% rename from tests/output/custom/category/yeah.html rename to pelican/tests/output/custom/category/yeah.html index ece5f0eb..a632664f 100644 --- a/tests/output/custom/category/yeah.html +++ b/pelican/tests/output/custom/category/yeah.html @@ -1,154 +1,91 @@ - Alexis' log - yeah - - + Alexis' log - yeah + - - - - - - - - + + - - Fork me on GitHub - - - - - - - - - - - - - - - - - -
    - - - -
    - - - - - \ No newline at end of file + diff --git a/pelican/tests/output/custom/drafts/a-draft-article.html b/pelican/tests/output/custom/drafts/a-draft-article.html new file mode 100644 index 00000000..15a3f1db --- /dev/null +++ b/pelican/tests/output/custom/drafts/a-draft-article.html @@ -0,0 +1,100 @@ + + + + + A draft article + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + A draft article

    +
    + +
    +

    This is a draft article, it should live under the /drafts/ folder and not be +listed anywhere else.

    + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/pelican/tests/output/custom/feeds/alexis-metaireau.atom.xml b/pelican/tests/output/custom/feeds/alexis-metaireau.atom.xml new file mode 100644 index 00000000..cb746377 --- /dev/null +++ b/pelican/tests/output/custom/feeds/alexis-metaireau.atom.xml @@ -0,0 +1,61 @@ + +Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:filename_metadata-example.html<p>Some cool stuff!</p> +Second article2012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:second-article.html<p>This is some article, in english</p> +A markdown powered article2011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:a-markdown-powered-article.html<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:article-1.html<p>Article 1</p> +Article 22011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:article-2.html<p>Article 2</p> +Article 32011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:article-3.html<p>Article 3</p> +This is a super article !2013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:this-is-a-super-article.html<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Oh yeah !2010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:oh-yeah.html<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Unbelievable !2010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:unbelievable.html<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +The baz tag2010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> + \ No newline at end of file diff --git a/pelican/tests/output/custom/feeds/alexis-metaireau.rss.xml b/pelican/tests/output/custom/feeds/alexis-metaireau.rss.xml new file mode 100644 index 00000000..2c4b1160 --- /dev/null +++ b/pelican/tests/output/custom/feeds/alexis-metaireau.rss.xml @@ -0,0 +1,61 @@ + +Alexis' loghttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/filename_metadata-example.html<p>Some cool stuff!</p> +Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:filename_metadata-example.htmlSecond articlehttp://blog.notmyidea.org/second-article.html<p>This is some article, in english</p> +Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:second-article.htmlfoobarbazA markdown powered articlehttp://blog.notmyidea.org/a-markdown-powered-article.html<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:a-markdown-powered-article.htmlArticle 1http://blog.notmyidea.org/article-1.html<p>Article 1</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:article-1.htmlArticle 2http://blog.notmyidea.org/article-2.html<p>Article 2</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:article-2.htmlArticle 3http://blog.notmyidea.org/article-3.html<p>Article 3</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:article-3.htmlThis is a super article !http://blog.notmyidea.org/this-is-a-super-article.html<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Alexis MétaireauSun, 17 Nov 2013 23:29:00 +0100tag:blog.notmyidea.org,2010-12-02:this-is-a-super-article.htmlfoobarfoobarOh yeah !http://blog.notmyidea.org/oh-yeah.html<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:oh-yeah.htmlohbaryeahUnbelievable !http://blog.notmyidea.org/unbelievable.html<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:unbelievable.htmlThe baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> +Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:tag/baz.html \ No newline at end of file diff --git a/pelican/tests/output/custom/feeds/all-en.atom.xml b/pelican/tests/output/custom/feeds/all-en.atom.xml new file mode 100644 index 00000000..3574ab42 --- /dev/null +++ b/pelican/tests/output/custom/feeds/all-en.atom.xml @@ -0,0 +1,61 @@ + +Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:filename_metadata-example.html<p>Some cool stuff!</p> +Second article2012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:second-article.html<p>This is some article, in english</p> +A markdown powered article2011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:a-markdown-powered-article.html<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:article-1.html<p>Article 1</p> +Article 22011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:article-2.html<p>Article 2</p> +Article 32011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:article-3.html<p>Article 3</p> +This is a super article !2013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:this-is-a-super-article.html<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Oh yeah !2010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:oh-yeah.html<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Unbelievable !2010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:unbelievable.html<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +The baz tag2010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> + \ No newline at end of file diff --git a/tests/output/custom/feeds/all-fr.atom.xml b/pelican/tests/output/custom/feeds/all-fr.atom.xml similarity index 100% rename from tests/output/custom/feeds/all-fr.atom.xml rename to pelican/tests/output/custom/feeds/all-fr.atom.xml diff --git a/pelican/tests/output/custom/feeds/all.atom.xml b/pelican/tests/output/custom/feeds/all.atom.xml new file mode 100644 index 00000000..391ab85f --- /dev/null +++ b/pelican/tests/output/custom/feeds/all.atom.xml @@ -0,0 +1,63 @@ + +Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:filename_metadata-example.html<p>Some cool stuff!</p> +Trop bien !2012-03-02T14:01:01+01:00Alexis Métaireautag:blog.notmyidea.org,2012-03-02:oh-yeah-fr.html<p>Et voila du contenu en français</p> +Second article2012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:second-article.html<p>This is some article, in english</p> +Deuxième article2012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:second-article-fr.html<p>Ceci est un article, en français.</p> +A markdown powered article2011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:a-markdown-powered-article.html<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:article-1.html<p>Article 1</p> +Article 22011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:article-2.html<p>Article 2</p> +Article 32011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:article-3.html<p>Article 3</p> +This is a super article !2013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:this-is-a-super-article.html<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Oh yeah !2010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:oh-yeah.html<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Unbelievable !2010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:unbelievable.html<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +The baz tag2010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> + \ No newline at end of file diff --git a/pelican/tests/output/custom/feeds/all.rss.xml b/pelican/tests/output/custom/feeds/all.rss.xml new file mode 100644 index 00000000..a78d2dec --- /dev/null +++ b/pelican/tests/output/custom/feeds/all.rss.xml @@ -0,0 +1,63 @@ + +Alexis' loghttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/filename_metadata-example.html<p>Some cool stuff!</p> +Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:filename_metadata-example.htmlTrop bien !http://blog.notmyidea.org/oh-yeah-fr.html<p>Et voila du contenu en français</p> +Alexis MétaireauFri, 02 Mar 2012 14:01:01 +0100tag:blog.notmyidea.org,2012-03-02:oh-yeah-fr.htmlSecond articlehttp://blog.notmyidea.org/second-article.html<p>This is some article, in english</p> +Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:second-article.htmlfoobarbazDeuxième articlehttp://blog.notmyidea.org/second-article-fr.html<p>Ceci est un article, en français.</p> +Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:second-article-fr.htmlfoobarbazA markdown powered articlehttp://blog.notmyidea.org/a-markdown-powered-article.html<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:a-markdown-powered-article.htmlArticle 1http://blog.notmyidea.org/article-1.html<p>Article 1</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:article-1.htmlArticle 2http://blog.notmyidea.org/article-2.html<p>Article 2</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:article-2.htmlArticle 3http://blog.notmyidea.org/article-3.html<p>Article 3</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:article-3.htmlThis is a super article !http://blog.notmyidea.org/this-is-a-super-article.html<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Alexis MétaireauSun, 17 Nov 2013 23:29:00 +0100tag:blog.notmyidea.org,2010-12-02:this-is-a-super-article.htmlfoobarfoobarOh yeah !http://blog.notmyidea.org/oh-yeah.html<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:oh-yeah.htmlohbaryeahUnbelievable !http://blog.notmyidea.org/unbelievable.html<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:unbelievable.htmlThe baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> +Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:tag/baz.html \ No newline at end of file diff --git a/tests/output/custom/feeds/bar.atom.xml b/pelican/tests/output/custom/feeds/bar.atom.xml similarity index 88% rename from tests/output/custom/feeds/bar.atom.xml rename to pelican/tests/output/custom/feeds/bar.atom.xml index 9b29f6c9..99b7cc45 100644 --- a/tests/output/custom/feeds/bar.atom.xml +++ b/pelican/tests/output/custom/feeds/bar.atom.xml @@ -3,6 +3,6 @@ <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> -<img alt="alternate text" src="pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> \ No newline at end of file diff --git a/tests/output/custom/feeds/bar.rss.xml b/pelican/tests/output/custom/feeds/bar.rss.xml similarity index 82% rename from tests/output/custom/feeds/bar.rss.xml rename to pelican/tests/output/custom/feeds/bar.rss.xml index c958edbf..94bd93f2 100644 --- a/tests/output/custom/feeds/bar.rss.xml +++ b/pelican/tests/output/custom/feeds/bar.rss.xml @@ -1,8 +1,8 @@ -Alexis' loghttp://blog.notmyidea.org/Wed, 20 Oct 2010 10:14:00 +0200Oh yeah !http://blog.notmyidea.org/oh-yeah.html<div class="section" id="why-not"> +Alexis' loghttp://blog.notmyidea.org/Wed, 20 Oct 2010 10:14:00 +0200Oh yeah !http://blog.notmyidea.org/oh-yeah.html<div class="section" id="why-not"> <h2>Why not ?</h2> <p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !</p> -<img alt="alternate text" src="pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> </div> Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:oh-yeah.htmlohbaryeah \ No newline at end of file diff --git a/tests/output/custom/feeds/cat1.atom.xml b/pelican/tests/output/custom/feeds/cat1.atom.xml similarity index 70% rename from tests/output/custom/feeds/cat1.atom.xml rename to pelican/tests/output/custom/feeds/cat1.atom.xml index 72703065..5454ce4d 100644 --- a/tests/output/custom/feeds/cat1.atom.xml +++ b/pelican/tests/output/custom/feeds/cat1.atom.xml @@ -1,5 +1,7 @@ -Alexis' loghttp://blog.notmyidea.org/2011-04-20T00:00:00+02:00A markdown powered article2011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:a-markdown-powered-article.html<p>You're mutually oblivious.</p>Article 12011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:article-1.html<p>Article 1</p> +Alexis' loghttp://blog.notmyidea.org/2011-04-20T00:00:00+02:00A markdown powered article2011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:a-markdown-powered-article.html<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:article-1.html<p>Article 1</p> Article 22011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:article-2.html<p>Article 2</p> Article 32011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:article-3.html<p>Article 3</p> \ No newline at end of file diff --git a/tests/output/custom/feeds/cat1.rss.xml b/pelican/tests/output/custom/feeds/cat1.rss.xml similarity index 65% rename from tests/output/custom/feeds/cat1.rss.xml rename to pelican/tests/output/custom/feeds/cat1.rss.xml index f5871487..62b93fd1 100644 --- a/tests/output/custom/feeds/cat1.rss.xml +++ b/pelican/tests/output/custom/feeds/cat1.rss.xml @@ -1,5 +1,7 @@ -Alexis' loghttp://blog.notmyidea.org/Wed, 20 Apr 2011 00:00:00 +0200A markdown powered articlehttp://blog.notmyidea.org/a-markdown-powered-article.html<p>You're mutually oblivious.</p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:a-markdown-powered-article.htmlArticle 1http://blog.notmyidea.org/article-1.html<p>Article 1</p> +Alexis' loghttp://blog.notmyidea.org/Wed, 20 Apr 2011 00:00:00 +0200A markdown powered articlehttp://blog.notmyidea.org/a-markdown-powered-article.html<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/unbelievable.html">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/unbelievable.html">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:a-markdown-powered-article.htmlArticle 1http://blog.notmyidea.org/article-1.html<p>Article 1</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:article-1.htmlArticle 2http://blog.notmyidea.org/article-2.html<p>Article 2</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:article-2.htmlArticle 3http://blog.notmyidea.org/article-3.html<p>Article 3</p> Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:article-3.html \ No newline at end of file diff --git a/pelican/tests/output/custom/feeds/misc.atom.xml b/pelican/tests/output/custom/feeds/misc.atom.xml new file mode 100644 index 00000000..91d6b28f --- /dev/null +++ b/pelican/tests/output/custom/feeds/misc.atom.xml @@ -0,0 +1,38 @@ + +Alexis' loghttp://blog.notmyidea.org/2012-11-30T00:00:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:filename_metadata-example.html<p>Some cool stuff!</p> +Second article2012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:second-article.html<p>This is some article, in english</p> +Unbelievable !2010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:unbelievable.html<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +The baz tag2010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> + \ No newline at end of file diff --git a/pelican/tests/output/custom/feeds/misc.rss.xml b/pelican/tests/output/custom/feeds/misc.rss.xml new file mode 100644 index 00000000..3493d2a3 --- /dev/null +++ b/pelican/tests/output/custom/feeds/misc.rss.xml @@ -0,0 +1,38 @@ + +Alexis' loghttp://blog.notmyidea.org/Fri, 30 Nov 2012 00:00:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/filename_metadata-example.html<p>Some cool stuff!</p> +Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:filename_metadata-example.htmlSecond articlehttp://blog.notmyidea.org/second-article.html<p>This is some article, in english</p> +Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:second-article.htmlfoobarbazUnbelievable !http://blog.notmyidea.org/unbelievable.html<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/a-markdown-powered-article.html">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:unbelievable.htmlThe baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> +Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:tag/baz.html \ No newline at end of file diff --git a/tests/output/custom/feeds/yeah.atom.xml b/pelican/tests/output/custom/feeds/yeah.atom.xml similarity index 66% rename from tests/output/custom/feeds/yeah.atom.xml rename to pelican/tests/output/custom/feeds/yeah.atom.xml index 802f6329..bd1da591 100644 --- a/tests/output/custom/feeds/yeah.atom.xml +++ b/pelican/tests/output/custom/feeds/yeah.atom.xml @@ -1,10 +1,10 @@ -Alexis' loghttp://blog.notmyidea.org/2010-12-02T10:14:00+01:00This is a super article !2010-12-02T10:14:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:this-is-a-super-article.html<p>Some content here !</p> +Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00This is a super article !2013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:this-is-a-super-article.html<p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() diff --git a/tests/output/custom/feeds/yeah.rss.xml b/pelican/tests/output/custom/feeds/yeah.rss.xml similarity index 67% rename from tests/output/custom/feeds/yeah.rss.xml rename to pelican/tests/output/custom/feeds/yeah.rss.xml index 68e96cf9..f054d3a6 100644 --- a/tests/output/custom/feeds/yeah.rss.xml +++ b/pelican/tests/output/custom/feeds/yeah.rss.xml @@ -1,14 +1,14 @@ -Alexis' loghttp://blog.notmyidea.org/Thu, 02 Dec 2010 10:14:00 +0100This is a super article !http://blog.notmyidea.org/this-is-a-super-article.html<p>Some content here !</p> +Alexis' loghttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100This is a super article !http://blog.notmyidea.org/this-is-a-super-article.html<p>Some content here !</p> <div class="section" id="this-is-a-simple-title"> <h2>This is a simple title</h2> <p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> -<img alt="alternate text" src="pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> -<img alt="alternate text" src="pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> <pre class="literal-block"> &gt;&gt;&gt; from ipdb import set_trace &gt;&gt;&gt; set_trace() </pre> <p>→ And now try with some utf8 hell: ééé</p> </div> -Alexis MétaireauThu, 02 Dec 2010 10:14:00 +0100tag:blog.notmyidea.org,2010-12-02:this-is-a-super-article.htmlfoobarfoobar \ No newline at end of file +Alexis MétaireauSun, 17 Nov 2013 23:29:00 +0100tag:blog.notmyidea.org,2010-12-02:this-is-a-super-article.htmlfoobarfoobar \ No newline at end of file diff --git a/tests/output/custom/unbelievable.html b/pelican/tests/output/custom/filename_metadata-example.html similarity index 67% rename from tests/output/custom/unbelievable.html rename to pelican/tests/output/custom/filename_metadata-example.html index e08b2952..047f12af 100644 --- a/tests/output/custom/unbelievable.html +++ b/pelican/tests/output/custom/filename_metadata-example.html @@ -1,143 +1,96 @@ - Unbelievable ! - - + FILENAME_METADATA example + - - - - - - - - + + - - Fork me on GitHub - - -

    - Unbelievable !

    - + FILENAME_METADATA example
    -
    - - Fri 15 October 2010 + -

    Or completely awesome. Depends the needs.

    +

    Some cool stuff!

    -

    Comments !

    +
    -
    -
    - - - -
    - - - - \ No newline at end of file diff --git a/tests/output/custom/index.html b/pelican/tests/output/custom/index.html similarity index 58% rename from tests/output/custom/index.html rename to pelican/tests/output/custom/index.html index 80913795..c375b208 100644 --- a/tests/output/custom/index.html +++ b/pelican/tests/output/custom/index.html @@ -1,259 +1,155 @@ - Alexis' log - - + Alexis' log + - - - - - - - - + + - - Fork me on GitHub - - - - - - - -

    Other articles


      - - - - - - - - -
    1. +
    2. + +
    3. - - - - - - -
    - -

    - - Page 1 / 2 - + Page 1 / 3 » -

    - -
    - - - -
    - - - -
    - - - - \ No newline at end of file diff --git a/tests/output/custom/index2.html b/pelican/tests/output/custom/index2.html similarity index 58% rename from tests/output/custom/index2.html rename to pelican/tests/output/custom/index2.html index 1eb336b6..1f2479d6 100644 --- a/tests/output/custom/index2.html +++ b/pelican/tests/output/custom/index2.html @@ -1,271 +1,169 @@ - Alexis' log - - + Alexis' log + - - - - - - - - + + - - Fork me on GitHub - - - - - - - -
      - -
    1. +
    2. + +
    3. - - - - - - -
    4. +
    5. - - - - - - -
    6. +
    7. - - - - - - - -
    8. - -
    - -

    - - - « - - - Page 2 / 2 - + « + Page 2 / 3 + »

    - -
    - - - -
    - - - -
    - - - - - \ No newline at end of file + diff --git a/pelican/tests/output/custom/index3.html b/pelican/tests/output/custom/index3.html new file mode 100644 index 00000000..e7e4f34a --- /dev/null +++ b/pelican/tests/output/custom/index3.html @@ -0,0 +1,138 @@ + + + + + Alexis' log + + + + + + + + + +Fork me on GitHub + + + +
    +
      +
    1. + +
    2. +
    +

    + « + Page 3 / 3 +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom/jinja2_template.html b/pelican/tests/output/custom/jinja2_template.html new file mode 100644 index 00000000..0eafa913 --- /dev/null +++ b/pelican/tests/output/custom/jinja2_template.html @@ -0,0 +1,77 @@ + + + + + Alexis' log + + + + + + + + + +Fork me on GitHub + + + +Some text + +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/tests/output/custom/oh-yeah-fr.html b/pelican/tests/output/custom/oh-yeah-fr.html similarity index 69% rename from tests/output/custom/oh-yeah-fr.html rename to pelican/tests/output/custom/oh-yeah-fr.html index fb669e9b..fa02ac2b 100644 --- a/tests/output/custom/oh-yeah-fr.html +++ b/pelican/tests/output/custom/oh-yeah-fr.html @@ -1,148 +1,98 @@ - Trop bien ! - - + Trop bien ! + - - - - - - - - + + - - Fork me on GitHub - - -

    - Trop bien !

    -
    -
    - - Fri 02 March 2012 + -

    Et voila du contenu en français

    +

    Et voila du contenu en français

    -

    Comments !

    +
    -
    -
    - - - -
    - - - - \ No newline at end of file diff --git a/tests/output/custom/oh-yeah.html b/pelican/tests/output/custom/oh-yeah.html similarity index 68% rename from tests/output/custom/oh-yeah.html rename to pelican/tests/output/custom/oh-yeah.html index c4eb421f..6d108cf2 100644 --- a/tests/output/custom/oh-yeah.html +++ b/pelican/tests/output/custom/oh-yeah.html @@ -1,153 +1,103 @@ - Oh yeah ! - - + Oh yeah ! + - - - - - - - - + + - - Fork me on GitHub - - -

    - Oh yeah !

    -
    -

    Why not ?

    After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! YEAH !

    -alternate text +alternate text
    -

    Comments !

    +
    -
    -
    - - - -
    - - - - \ No newline at end of file diff --git a/pelican/tests/output/custom/override/index.html b/pelican/tests/output/custom/override/index.html new file mode 100644 index 00000000..e84d79fe --- /dev/null +++ b/pelican/tests/output/custom/override/index.html @@ -0,0 +1,81 @@ + + + + + Override url/save_as + + + + + + + + + +Fork me on GitHub + + +
    +

    Override url/save_as

    + +

    Test page which overrides save_as and url so that this page will be generated +at a custom location.

    + +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/tests/output/custom/pages/this-is-a-test-hidden-page.html b/pelican/tests/output/custom/pages/this-is-a-test-hidden-page.html similarity index 66% rename from tests/output/custom/pages/this-is-a-test-hidden-page.html rename to pelican/tests/output/custom/pages/this-is-a-test-hidden-page.html index 913a5974..dced8107 100644 --- a/tests/output/custom/pages/this-is-a-test-hidden-page.html +++ b/pelican/tests/output/custom/pages/this-is-a-test-hidden-page.html @@ -1,105 +1,63 @@ - This is a test hidden page - - + This is a test hidden page + - - - - - - - - + + - - Fork me on GitHub - - - -
    +

    This is a test hidden page

    This is great for things like error(404) pages Anyone can see this page but it's not linked to anywhere!

    -
    - - - -
    @@ -110,18 +68,14 @@ Anyone can see this page but it's not linked to anywhere!

    The theme is by Smashing Magazine, thanks!

    - - - - \ No newline at end of file diff --git a/tests/output/custom/pages/this-is-a-test-page.html b/pelican/tests/output/custom/pages/this-is-a-test-page.html similarity index 64% rename from tests/output/custom/pages/this-is-a-test-page.html rename to pelican/tests/output/custom/pages/this-is-a-test-page.html index 87e4925f..46ea4fef 100644 --- a/tests/output/custom/pages/this-is-a-test-page.html +++ b/pelican/tests/output/custom/pages/this-is-a-test-page.html @@ -1,105 +1,63 @@ - This is a test page - - + This is a test page + - - - - - - - - + + - - Fork me on GitHub - - - -
    +

    This is a test page

    Just an image.

    -alternate text +alternate text
    -
    - - - -
    - - - - \ No newline at end of file diff --git a/tests/output/custom/static/pictures/Fat_Cat.jpg b/pelican/tests/output/custom/pictures/Fat_Cat.jpg similarity index 100% rename from tests/output/custom/static/pictures/Fat_Cat.jpg rename to pelican/tests/output/custom/pictures/Fat_Cat.jpg diff --git a/tests/output/custom/static/pictures/Sushi.jpg b/pelican/tests/output/custom/pictures/Sushi.jpg similarity index 100% rename from tests/output/custom/static/pictures/Sushi.jpg rename to pelican/tests/output/custom/pictures/Sushi.jpg diff --git a/tests/output/custom/static/pictures/Sushi_Macro.jpg b/pelican/tests/output/custom/pictures/Sushi_Macro.jpg similarity index 100% rename from tests/output/custom/static/pictures/Sushi_Macro.jpg rename to pelican/tests/output/custom/pictures/Sushi_Macro.jpg diff --git a/pelican/tests/output/custom/robots.txt b/pelican/tests/output/custom/robots.txt new file mode 100644 index 00000000..19a6e299 --- /dev/null +++ b/pelican/tests/output/custom/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: /pictures diff --git a/tests/output/custom/second-article-fr.html b/pelican/tests/output/custom/second-article-fr.html similarity index 69% rename from tests/output/custom/second-article-fr.html rename to pelican/tests/output/custom/second-article-fr.html index 1100df29..6c537609 100644 --- a/tests/output/custom/second-article-fr.html +++ b/pelican/tests/output/custom/second-article-fr.html @@ -1,148 +1,98 @@ - Deuxième article - - + Deuxième article + - - - - - - - - + + - - Fork me on GitHub - - -

    - Deuxième article

    -
    -
    - - Wed 29 February 2012 + -

    Ceci est un article, en français.

    +

    Ceci est un article, en français.

    -

    Comments !

    +
    -
    -
    - - - -
    - - - - \ No newline at end of file diff --git a/tests/output/custom/second-article.html b/pelican/tests/output/custom/second-article.html similarity index 69% rename from tests/output/custom/second-article.html rename to pelican/tests/output/custom/second-article.html index 7a908526..30179205 100644 --- a/tests/output/custom/second-article.html +++ b/pelican/tests/output/custom/second-article.html @@ -1,148 +1,98 @@ - Second article - - + Second article + - - - - - - - - + + - - Fork me on GitHub - - -

    - Second article

    -
    -
    - - Wed 29 February 2012 + -

    This is some article, in english

    +

    This is some article, in english

    -

    Comments !

    +
    -
    -
    - - - -
    - - - - \ No newline at end of file diff --git a/pelican/tests/output/custom/tag/bar.html b/pelican/tests/output/custom/tag/bar.html new file mode 100644 index 00000000..28cbbe75 --- /dev/null +++ b/pelican/tests/output/custom/tag/bar.html @@ -0,0 +1,160 @@ + + + + + Alexis' log - bar + + + + + + + + + +Fork me on GitHub + + + + +
    +

    Other articles

    +
    +
      + +
    1. + +
    2. +
      +

      Oh yeah !

      +
      + +
      +
      +

      Why not ?

      +

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !

      +alternate text +
      + + read more +

      There are comments.

      +
    3. +
    +

    + Page 1 / 1 +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/pelican/tests/output/custom/tag/baz.html b/pelican/tests/output/custom/tag/baz.html new file mode 100644 index 00000000..06f3c301 --- /dev/null +++ b/pelican/tests/output/custom/tag/baz.html @@ -0,0 +1,114 @@ + + + + + The baz tag + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + The baz tag

    +
    + +
    +

    This article overrides the listening of the articles under the baz tag.

    + +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/tests/output/custom/category/misc.html b/pelican/tests/output/custom/tag/foo.html similarity index 52% rename from tests/output/custom/category/misc.html rename to pelican/tests/output/custom/tag/foo.html index a0ac83a5..ba3c843e 100644 --- a/tests/output/custom/category/misc.html +++ b/pelican/tests/output/custom/tag/foo.html @@ -1,188 +1,112 @@ - Alexis' log - misc - - + Alexis' log - foo + - - - - - - - - + + - - Fork me on GitHub - - - - - - - -

    Other articles


      - - - - - - - - -
    - -

    - Page 1 / 1 -

    - -
    - - - -
    - - - -
    - - - - - \ No newline at end of file + diff --git a/tests/output/custom/tag/foobar.html b/pelican/tests/output/custom/tag/foobar.html similarity index 57% rename from tests/output/custom/tag/foobar.html rename to pelican/tests/output/custom/tag/foobar.html index cad2dae3..dc51889a 100644 --- a/tests/output/custom/tag/foobar.html +++ b/pelican/tests/output/custom/tag/foobar.html @@ -1,154 +1,91 @@ - Alexis' log - foobar - - + Alexis' log - foobar + - - - - - - - - + + - - Fork me on GitHub - - - - - - - - - - - - - -
    - - - -
    - - - -
    - - - - - \ No newline at end of file + diff --git a/pelican/tests/output/custom/tag/oh.html b/pelican/tests/output/custom/tag/oh.html new file mode 100644 index 00000000..21c8e352 --- /dev/null +++ b/pelican/tests/output/custom/tag/oh.html @@ -0,0 +1,80 @@ + + + + + Oh Oh Oh + + + + + + + + + +Fork me on GitHub + + +
    +

    Oh Oh Oh

    + +

    This page overrides the listening of the articles under the oh tag.

    + +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom/tag/yeah.html b/pelican/tests/output/custom/tag/yeah.html new file mode 100644 index 00000000..3b09c6c5 --- /dev/null +++ b/pelican/tests/output/custom/tag/yeah.html @@ -0,0 +1,101 @@ + + + + + Alexis' log - yeah + + + + + + + + + +Fork me on GitHub + + + + +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/pelican/tests/output/custom/tags.html b/pelican/tests/output/custom/tags.html new file mode 100644 index 00000000..ba8d53a4 --- /dev/null +++ b/pelican/tests/output/custom/tags.html @@ -0,0 +1,87 @@ + + + + + Alexis' log - Tags + + + + + + + + + +Fork me on GitHub + + + +
    +

    Tags for Alexis' log

    + +
    + +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/tests/output/basic/theme/css/main.css b/pelican/tests/output/custom/theme/css/main.css similarity index 84% rename from tests/output/basic/theme/css/main.css rename to pelican/tests/output/custom/theme/css/main.css index 3d94200b..2efb518d 100644 --- a/tests/output/basic/theme/css/main.css +++ b/pelican/tests/output/custom/theme/css/main.css @@ -3,15 +3,16 @@ Date: July 2009 Description: Sample layout for HTML5 and CSS3 goodness. Version: 1.0 - Author: Enrique Ramírez - Autor URI: http://enrique-ramirez.com + License: MIT + Licensed by: Smashing Media GmbH + Original author: Enrique Ramírez */ /* Imports */ @import url("reset.css"); @import url("pygment.css"); @import url("typogrify.css"); -@import url(http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz&subset=latin); +@import url(//fonts.googleapis.com/css?family=Yanone+Kaffeesatz&subset=latin); /***** Global *****/ /* Body */ @@ -65,7 +66,9 @@ h1 a:hover { } /* Paragraphs */ -p {margin-bottom: 1.143em;} +div.line-block, +p { margin-top: 1em; + margin-bottom: 1em;} strong, b {font-weight: bold;} em, i {font-style: italic;} @@ -73,14 +76,16 @@ em, i {font-style: italic;} /* Lists */ ul { list-style: outside disc; - margin: 1em 0 1.5em 1.5em; + margin: 0em 0 0 1.5em; } ol { list-style: outside decimal; - margin: 1em 0 1.5em 1.5em; + margin: 0em 0 0 1.5em; } +li { margin-top: 0.5em;} + .post-info { float:right; margin:10px; @@ -88,6 +93,7 @@ ol { } .post-info p{ + margin-top: 1px; margin-bottom: 1px; } @@ -301,15 +307,32 @@ img.left, figure.left {float: left; margin: 0 2em 2em 0;} } /* Icons */ + .social a[href*='about.me'] {background-image: url('../images/icons/aboutme.png');} + .social a[href*='bitbucket.org'] {background-image: url('../images/icons/bitbucket.png');} .social a[href*='delicious.com'] {background-image: url('../images/icons/delicious.png');} .social a[href*='digg.com'] {background-image: url('../images/icons/digg.png');} .social a[href*='facebook.com'] {background-image: url('../images/icons/facebook.png');} - .social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');} - .social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('../images/icons/rss.png');} - .social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');} - .social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');} .social a[href*='gitorious.org'] {background-image: url('../images/icons/gitorious.png');} - .social a[href*='gittip.com'] {background-image: url('../images/icons/gittip.png');} + .social a[href*='github.com'], + .social a[href*='git.io'] { + background-image: url('../images/icons/github.png'); + background-size: 16px 16px; + } + .social a[href*='gittip.com'] {background-image: url('../images/icons/gittip.png');} + .social a[href*='plus.google.com'] {background-image: url('../images/icons/google-plus.png');} + .social a[href*='groups.google.com'] {background-image: url('../images/icons/google-groups.png');} + .social a[href*='news.ycombinator.com'], + .social a[href*='hackernewsers.com'] {background-image: url('../images/icons/hackernews.png');} + .social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');} + .social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');} + .social a[href*='reddit.com'] {background-image: url('../images/icons/reddit.png');} + .social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('../images/icons/rss.png');} + .social a[href*='slideshare.net'] {background-image: url('../images/icons/slideshare.png');} + .social a[href*='speakerdeck.com'] {background-image: url('../images/icons/speakerdeck.png');} + .social a[href*='stackoverflow.com'] {background-image: url('../images/icons/stackoverflow.png');} + .social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');} + .social a[href*='vimeo.com'] {background-image: url('../images/icons/vimeo.png');} + .social a[href*='youtube.com'] {background-image: url('../images/icons/youtube.png');} /* About diff --git a/tests/output/custom/theme/css/pygment.css b/pelican/tests/output/custom/theme/css/pygment.css similarity index 100% rename from tests/output/custom/theme/css/pygment.css rename to pelican/tests/output/custom/theme/css/pygment.css diff --git a/tests/output/custom/theme/css/reset.css b/pelican/tests/output/custom/theme/css/reset.css similarity index 100% rename from tests/output/custom/theme/css/reset.css rename to pelican/tests/output/custom/theme/css/reset.css diff --git a/tests/output/custom/theme/css/typogrify.css b/pelican/tests/output/custom/theme/css/typogrify.css similarity index 100% rename from tests/output/custom/theme/css/typogrify.css rename to pelican/tests/output/custom/theme/css/typogrify.css diff --git a/tests/output/custom/theme/css/wide.css b/pelican/tests/output/custom/theme/css/wide.css similarity index 100% rename from tests/output/custom/theme/css/wide.css rename to pelican/tests/output/custom/theme/css/wide.css diff --git a/pelican/tests/output/custom/theme/images/icons/aboutme.png b/pelican/tests/output/custom/theme/images/icons/aboutme.png new file mode 100644 index 00000000..9609df3b Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/aboutme.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/bitbucket.png b/pelican/tests/output/custom/theme/images/icons/bitbucket.png new file mode 100644 index 00000000..d05ba161 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/bitbucket.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/delicious.png b/pelican/tests/output/custom/theme/images/icons/delicious.png new file mode 100644 index 00000000..3dccdd84 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/delicious.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/facebook.png b/pelican/tests/output/custom/theme/images/icons/facebook.png new file mode 100644 index 00000000..74e7ad52 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/facebook.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/github.png b/pelican/tests/output/custom/theme/images/icons/github.png new file mode 100644 index 00000000..8b25551a Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/github.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/gitorious.png b/pelican/tests/output/custom/theme/images/icons/gitorious.png new file mode 100644 index 00000000..3eeb3ece Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/gitorious.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/gittip.png b/pelican/tests/output/custom/theme/images/icons/gittip.png new file mode 100644 index 00000000..af949625 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/gittip.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/google-groups.png b/pelican/tests/output/custom/theme/images/icons/google-groups.png new file mode 100644 index 00000000..5de15e68 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/google-groups.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/google-plus.png b/pelican/tests/output/custom/theme/images/icons/google-plus.png new file mode 100644 index 00000000..3c6b7432 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/google-plus.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/hackernews.png b/pelican/tests/output/custom/theme/images/icons/hackernews.png new file mode 100644 index 00000000..fc7a82d4 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/hackernews.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/lastfm.png b/pelican/tests/output/custom/theme/images/icons/lastfm.png new file mode 100644 index 00000000..3a6c6262 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/lastfm.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/linkedin.png b/pelican/tests/output/custom/theme/images/icons/linkedin.png new file mode 100644 index 00000000..d29c1201 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/linkedin.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/reddit.png b/pelican/tests/output/custom/theme/images/icons/reddit.png new file mode 100644 index 00000000..71ae1215 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/reddit.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/rss.png b/pelican/tests/output/custom/theme/images/icons/rss.png new file mode 100644 index 00000000..7862c65a Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/rss.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/slideshare.png b/pelican/tests/output/custom/theme/images/icons/slideshare.png new file mode 100644 index 00000000..ecc97410 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/slideshare.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/speakerdeck.png b/pelican/tests/output/custom/theme/images/icons/speakerdeck.png new file mode 100644 index 00000000..087d0931 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/speakerdeck.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/stackoverflow.png b/pelican/tests/output/custom/theme/images/icons/stackoverflow.png new file mode 100644 index 00000000..f5b65e99 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/stackoverflow.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/twitter.png b/pelican/tests/output/custom/theme/images/icons/twitter.png new file mode 100644 index 00000000..d0ef3cc1 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/twitter.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/vimeo.png b/pelican/tests/output/custom/theme/images/icons/vimeo.png new file mode 100644 index 00000000..dba47202 Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/vimeo.png differ diff --git a/pelican/tests/output/custom/theme/images/icons/youtube.png b/pelican/tests/output/custom/theme/images/icons/youtube.png new file mode 100644 index 00000000..ce6cbe4f Binary files /dev/null and b/pelican/tests/output/custom/theme/images/icons/youtube.png differ diff --git a/tests/output/custom/this-is-a-super-article.html b/pelican/tests/output/custom/this-is-a-super-article.html similarity index 69% rename from tests/output/custom/this-is-a-super-article.html rename to pelican/tests/output/custom/this-is-a-super-article.html index f1e3fa40..34ab434e 100644 --- a/tests/output/custom/this-is-a-super-article.html +++ b/pelican/tests/output/custom/this-is-a-super-article.html @@ -1,88 +1,62 @@ - This is a super article ! - - + This is a super article ! + - - - - - - - - + + - - Fork me on GitHub - - -

    - This is a super article !

    -
    -
    - - Thu 02 December 2010 + -

    Some content here !

    +

    Some content here !

    This is a simple title

    And here comes the cool stuff.

    -alternate text -alternate text +alternate text +alternate text
     >>> from ipdb import set_trace
     >>> set_trace()
    @@ -91,64 +65,47 @@
     
    -

    Comments !

    +
    -
    -
    - - - -
    - - - - - \ No newline at end of file + diff --git a/pelican/tests/output/custom/unbelievable.html b/pelican/tests/output/custom/unbelievable.html new file mode 100644 index 00000000..395cd1b6 --- /dev/null +++ b/pelican/tests/output/custom/unbelievable.html @@ -0,0 +1,146 @@ + + + + + Unbelievable ! + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + Unbelievable !

    +
    + +
    +

    Or completely awesome. Depends the needs.

    +

    a root-relative link to markdown-article +a file-relative link to markdown-article

    +
    +

    Testing sourcecode directive

    +
    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    +
    +
    +
    +

    Testing another case

    +

    This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.

    +
    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    +
    +

    Lovely.

    +
    +
    +

    Testing more sourcecode directives

    +
     8 def run(self):
    self.assert_has_content()
    10 try:
    lexer = get_lexer_by_name(self.arguments[0])
    12 except ValueError:
    # no lexer found - use the text one instead of an exception
    14 lexer = TextLexer()

    16 if ('linenos' in self.options and
    self.options['linenos'] not in ('table', 'inline')):
    18 self.options['linenos'] = 'table'

    20 for flag in ('nowrap', 'nobackground', 'anchorlinenos'):
    if flag in self.options:
    22 self.options[flag] = True

    24 # noclasses should already default to False, but just in case...
    formatter = HtmlFormatter(noclasses=False, **self.options)
    26 parsed = highlight('\n'.join(self.content), lexer, formatter)
    return [nodes.raw('', parsed, format='html')]
    +

    Lovely.

    +
    +
    +

    Testing even more sourcecode directives

    +formatter = self.options and VARIANTS[self.options.keys()[0]] +

    Lovely.

    +
    +
    +

    Testing overriding config defaults

    +

    Even if the default is line numbers, we can override it here

    +
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    +
    +

    Lovely.

    +
    + +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/archives.html b/pelican/tests/output/custom_locale/archives.html new file mode 100644 index 00000000..1336b487 --- /dev/null +++ b/pelican/tests/output/custom_locale/archives.html @@ -0,0 +1,100 @@ + + + + + Alexis' log + + + + + + + + + +Fork me on GitHub + + +
    +

    Archives for Alexis' log

    + +
    +
    30 novembre 2012
    +
    FILENAME_METADATA example
    +
    29 février 2012
    +
    Second article
    +
    20 avril 2011
    +
    A markdown powered article
    +
    17 février 2011
    +
    Article 1
    +
    17 février 2011
    +
    Article 2
    +
    17 février 2011
    +
    Article 3
    +
    02 décembre 2010
    +
    This is a super article !
    +
    20 octobre 2010
    +
    Oh yeah !
    +
    15 octobre 2010
    +
    Unbelievable !
    +
    14 mars 2010
    +
    The baz tag
    +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/author/alexis-metaireau.html b/pelican/tests/output/custom_locale/author/alexis-metaireau.html new file mode 100644 index 00000000..1882015e --- /dev/null +++ b/pelican/tests/output/custom_locale/author/alexis-metaireau.html @@ -0,0 +1,173 @@ + + + + + Alexis' log - Alexis Métaireau + + + + + + + + + +Fork me on GitHub + + + + +
    +

    Other articles

    +
    +
      + +
    1. + +
    2. + +
    3. +
    +

    + Page 1 / 3 + » +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/author/alexis-metaireau2.html b/pelican/tests/output/custom_locale/author/alexis-metaireau2.html new file mode 100644 index 00000000..d1b50107 --- /dev/null +++ b/pelican/tests/output/custom_locale/author/alexis-metaireau2.html @@ -0,0 +1,187 @@ + + + + + Alexis' log - Alexis Métaireau + + + + + + + + + +Fork me on GitHub + + + +
    +
      +
    1. + +
    2. + +
    3. + +
    4. +
      +

      Oh yeah !

      +
      + +
      +
      +

      Why not ?

      +

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !

      +alternate text +
      + + read more +

      There are comments.

      +
    5. +
    +

    + « + Page 2 / 3 + » +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/pelican/tests/output/custom_locale/author/alexis-metaireau3.html b/pelican/tests/output/custom_locale/author/alexis-metaireau3.html new file mode 100644 index 00000000..333ef320 --- /dev/null +++ b/pelican/tests/output/custom_locale/author/alexis-metaireau3.html @@ -0,0 +1,138 @@ + + + + + Alexis' log - Alexis Métaireau + + + + + + + + + +Fork me on GitHub + + + +
    +
      +
    1. + +
    2. +
    +

    + « + Page 3 / 3 +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/authors.html b/pelican/tests/output/custom_locale/authors.html new file mode 100644 index 00000000..2558c4d8 --- /dev/null +++ b/pelican/tests/output/custom_locale/authors.html @@ -0,0 +1,82 @@ + + + + + Alexis' log - Authors + + + + + + + + + +Fork me on GitHub + + + +
    +

    Authors on Alexis' log

    + +
    + +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/categories.html b/pelican/tests/output/custom_locale/categories.html new file mode 100644 index 00000000..17d9de76 --- /dev/null +++ b/pelican/tests/output/custom_locale/categories.html @@ -0,0 +1,80 @@ + + + + + Alexis' log + + + + + + + + + +Fork me on GitHub + + + +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/tests/output/custom/category/bar.html b/pelican/tests/output/custom_locale/category/bar.html similarity index 57% rename from tests/output/custom/category/bar.html rename to pelican/tests/output/custom_locale/category/bar.html index e645f4e2..fc11f06e 100644 --- a/tests/output/custom/category/bar.html +++ b/pelican/tests/output/custom_locale/category/bar.html @@ -1,153 +1,83 @@ - Alexis' log - bar - - + Alexis' log - bar + - - - - - - - - + + - - Fork me on GitHub - - - - - - - - - - - - - -
    - - - -
    - - - -
    - - - - \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/category/cat1.html b/pelican/tests/output/custom_locale/category/cat1.html new file mode 100644 index 00000000..e1556d9e --- /dev/null +++ b/pelican/tests/output/custom_locale/category/cat1.html @@ -0,0 +1,170 @@ + + + + + Alexis' log - cat1 + + + + + + + + + +Fork me on GitHub + + + + +
    +

    Other articles

    +
    +
      + +
    1. + +
    2. + +
    3. +
    +

    + Page 1 / 1 +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/category/misc.html b/pelican/tests/output/custom_locale/category/misc.html new file mode 100644 index 00000000..3ff2f8e4 --- /dev/null +++ b/pelican/tests/output/custom_locale/category/misc.html @@ -0,0 +1,181 @@ + + + + + Alexis' log - misc + + + + + + + + + +Fork me on GitHub + + + + +
    +

    Other articles

    +
    +
      + +
    1. + +
    2. + +
    3. +
    +

    + Page 1 / 1 +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/category/yeah.html b/pelican/tests/output/custom_locale/category/yeah.html new file mode 100644 index 00000000..7ee2bbe9 --- /dev/null +++ b/pelican/tests/output/custom_locale/category/yeah.html @@ -0,0 +1,109 @@ + + + + + Alexis' log - yeah + + + + + + + + + +Fork me on GitHub + + + + +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/tests/output/custom/drafts/a-draft-article.html b/pelican/tests/output/custom_locale/drafts/a-draft-article.html similarity index 57% rename from tests/output/custom/drafts/a-draft-article.html rename to pelican/tests/output/custom_locale/drafts/a-draft-article.html index e38fb7b2..a33e6797 100644 --- a/tests/output/custom/drafts/a-draft-article.html +++ b/pelican/tests/output/custom_locale/drafts/a-draft-article.html @@ -1,144 +1,82 @@ - A draft article - - + A draft article + - - - - - - - - + + - - Fork me on GitHub - - -

    - A draft article

    -
    -

    This is a draft article, it should live under the /drafts/ folder and not be listed anywhere else.

    - -
    -

    Comments !

    -
    - -
    -
    -
    - - - -
    @@ -149,18 +87,14 @@ listed anywhere else.

    The theme is by Smashing Magazine, thanks!

    - - - - \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/alexis-metaireau.atom.xml b/pelican/tests/output/custom_locale/feeds/alexis-metaireau.atom.xml new file mode 100644 index 00000000..8fb3ef64 --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/alexis-metaireau.atom.xml @@ -0,0 +1,61 @@ + +Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> +Second article2012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:posts/2012/février/29/second-article/<p>This is some article, in english</p> +A markdown powered article2011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-1/<p>Article 1</p> +Article 22011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-2/<p>Article 2</p> +Article 32011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-3/<p>Article 3</p> +This is a super article !2013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:posts/2010/décembre/02/this-is-a-super-article/<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Oh yeah !2010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Unbelievable !2010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +The baz tag2010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/alexis-metaireau.rss.xml b/pelican/tests/output/custom_locale/feeds/alexis-metaireau.rss.xml new file mode 100644 index 00000000..99255ee5 --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/alexis-metaireau.rss.xml @@ -0,0 +1,61 @@ + +Alexis' loghttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> +Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:posts/2012/novembre/30/filename_metadata-example/Second articlehttp://blog.notmyidea.org/posts/2012/f%C3%A9vrier/29/second-article/<p>This is some article, in english</p> +Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:posts/2012/février/29/second-article/foobarbazA markdown powered articlehttp://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:posts/2011/avril/20/a-markdown-powered-article/Article 1http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-1/<p>Article 1</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-1/Article 2http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-2/<p>Article 2</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-2/Article 3http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-3/<p>Article 3</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-3/This is a super article !http://blog.notmyidea.org/posts/2010/d%C3%A9cembre/02/this-is-a-super-article/<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Alexis MétaireauSun, 17 Nov 2013 23:29:00 +0100tag:blog.notmyidea.org,2010-12-02:posts/2010/décembre/02/this-is-a-super-article/foobarfoobarOh yeah !http://blog.notmyidea.org/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:posts/2010/octobre/20/oh-yeah/ohbaryeahUnbelievable !http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:posts/2010/octobre/15/unbelievable/The baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> +Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:tag/baz.html \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/all-en.atom.xml b/pelican/tests/output/custom_locale/feeds/all-en.atom.xml new file mode 100644 index 00000000..6b2f09ba --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/all-en.atom.xml @@ -0,0 +1,61 @@ + +Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> +Second article2012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:posts/2012/février/29/second-article/<p>This is some article, in english</p> +A markdown powered article2011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-1/<p>Article 1</p> +Article 22011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-2/<p>Article 2</p> +Article 32011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-3/<p>Article 3</p> +This is a super article !2013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:posts/2010/décembre/02/this-is-a-super-article/<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Oh yeah !2010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Unbelievable !2010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +The baz tag2010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/all-fr.atom.xml b/pelican/tests/output/custom_locale/feeds/all-fr.atom.xml new file mode 100644 index 00000000..5d58742c --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/all-fr.atom.xml @@ -0,0 +1,4 @@ + +Alexis' loghttp://blog.notmyidea.org/2012-03-02T14:01:01+01:00Trop bien !2012-03-02T14:01:01+01:00Alexis Métaireautag:blog.notmyidea.org,2012-03-02:oh-yeah-fr.html<p>Et voila du contenu en français</p> +Deuxième article2012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:second-article-fr.html<p>Ceci est un article, en français.</p> + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/all.atom.xml b/pelican/tests/output/custom_locale/feeds/all.atom.xml new file mode 100644 index 00000000..5ef59e04 --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/all.atom.xml @@ -0,0 +1,63 @@ + +Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> +Trop bien !2012-03-02T14:01:01+01:00Alexis Métaireautag:blog.notmyidea.org,2012-03-02:oh-yeah-fr.html<p>Et voila du contenu en français</p> +Second article2012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:posts/2012/février/29/second-article/<p>This is some article, in english</p> +Deuxième article2012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:second-article-fr.html<p>Ceci est un article, en français.</p> +A markdown powered article2011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-1/<p>Article 1</p> +Article 22011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-2/<p>Article 2</p> +Article 32011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-3/<p>Article 3</p> +This is a super article !2013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:posts/2010/décembre/02/this-is-a-super-article/<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Oh yeah !2010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Unbelievable !2010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +The baz tag2010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/all.rss.xml b/pelican/tests/output/custom_locale/feeds/all.rss.xml new file mode 100644 index 00000000..071e2f1a --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/all.rss.xml @@ -0,0 +1,63 @@ + +Alexis' loghttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> +Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:posts/2012/novembre/30/filename_metadata-example/Trop bien !http://blog.notmyidea.org/oh-yeah-fr.html<p>Et voila du contenu en français</p> +Alexis MétaireauFri, 02 Mar 2012 14:01:01 +0100tag:blog.notmyidea.org,2012-03-02:oh-yeah-fr.htmlSecond articlehttp://blog.notmyidea.org/posts/2012/f%C3%A9vrier/29/second-article/<p>This is some article, in english</p> +Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:posts/2012/février/29/second-article/foobarbazDeuxième articlehttp://blog.notmyidea.org/second-article-fr.html<p>Ceci est un article, en français.</p> +Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:second-article-fr.htmlfoobarbazA markdown powered articlehttp://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:posts/2011/avril/20/a-markdown-powered-article/Article 1http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-1/<p>Article 1</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-1/Article 2http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-2/<p>Article 2</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-2/Article 3http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-3/<p>Article 3</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-3/This is a super article !http://blog.notmyidea.org/posts/2010/d%C3%A9cembre/02/this-is-a-super-article/<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Alexis MétaireauSun, 17 Nov 2013 23:29:00 +0100tag:blog.notmyidea.org,2010-12-02:posts/2010/décembre/02/this-is-a-super-article/foobarfoobarOh yeah !http://blog.notmyidea.org/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:posts/2010/octobre/20/oh-yeah/ohbaryeahUnbelievable !http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:posts/2010/octobre/15/unbelievable/The baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> +Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:tag/baz.html \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/bar.atom.xml b/pelican/tests/output/custom_locale/feeds/bar.atom.xml new file mode 100644 index 00000000..02fae916 --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/bar.atom.xml @@ -0,0 +1,8 @@ + +Alexis' loghttp://blog.notmyidea.org/2010-10-20T10:14:00+02:00Oh yeah !2010-10-20T10:14:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-20:posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/bar.rss.xml b/pelican/tests/output/custom_locale/feeds/bar.rss.xml new file mode 100644 index 00000000..96074958 --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/bar.rss.xml @@ -0,0 +1,8 @@ + +Alexis' loghttp://blog.notmyidea.org/Wed, 20 Oct 2010 10:14:00 +0200Oh yeah !http://blog.notmyidea.org/posts/2010/octobre/20/oh-yeah/<div class="section" id="why-not"> +<h2>Why not ?</h2> +<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +</div> +Alexis MétaireauWed, 20 Oct 2010 10:14:00 +0200tag:blog.notmyidea.org,2010-10-20:posts/2010/octobre/20/oh-yeah/ohbaryeah \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/cat1.atom.xml b/pelican/tests/output/custom_locale/feeds/cat1.atom.xml new file mode 100644 index 00000000..96f70900 --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/cat1.atom.xml @@ -0,0 +1,7 @@ + +Alexis' loghttp://blog.notmyidea.org/2011-04-20T00:00:00+02:00A markdown powered article2011-04-20T00:00:00+02:00Alexis Métaireautag:blog.notmyidea.org,2011-04-20:posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Article 12011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-1/<p>Article 1</p> +Article 22011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-2/<p>Article 2</p> +Article 32011-02-17T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-3/<p>Article 3</p> + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/cat1.rss.xml b/pelican/tests/output/custom_locale/feeds/cat1.rss.xml new file mode 100644 index 00000000..b78f51cc --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/cat1.rss.xml @@ -0,0 +1,7 @@ + +Alexis' loghttp://blog.notmyidea.org/Wed, 20 Apr 2011 00:00:00 +0200A markdown powered articlehttp://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/<p>You're mutually oblivious.</p> +<p><a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a root-relative link to unbelievable</a> +<a href="http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/">a file-relative link to unbelievable</a></p>Alexis MétaireauWed, 20 Apr 2011 00:00:00 +0200tag:blog.notmyidea.org,2011-04-20:posts/2011/avril/20/a-markdown-powered-article/Article 1http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-1/<p>Article 1</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-1/Article 2http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-2/<p>Article 2</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-2/Article 3http://blog.notmyidea.org/posts/2011/f%C3%A9vrier/17/article-3/<p>Article 3</p> +Alexis MétaireauThu, 17 Feb 2011 00:00:00 +0100tag:blog.notmyidea.org,2011-02-17:posts/2011/février/17/article-3/ \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/misc.atom.xml b/pelican/tests/output/custom_locale/feeds/misc.atom.xml new file mode 100644 index 00000000..c91d4d7e --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/misc.atom.xml @@ -0,0 +1,38 @@ + +Alexis' loghttp://blog.notmyidea.org/2012-11-30T00:00:00+01:00FILENAME_METADATA example2012-11-30T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-11-30:posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> +Second article2012-02-29T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2012-02-29:posts/2012/février/29/second-article/<p>This is some article, in english</p> +Unbelievable !2010-10-15T20:30:00+02:00Alexis Métaireautag:blog.notmyidea.org,2010-10-15:posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +The baz tag2010-03-14T00:00:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-03-14:tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/misc.rss.xml b/pelican/tests/output/custom_locale/feeds/misc.rss.xml new file mode 100644 index 00000000..82b58983 --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/misc.rss.xml @@ -0,0 +1,38 @@ + +Alexis' loghttp://blog.notmyidea.org/Fri, 30 Nov 2012 00:00:00 +0100FILENAME_METADATA examplehttp://blog.notmyidea.org/posts/2012/novembre/30/filename_metadata-example/<p>Some cool stuff!</p> +Alexis MétaireauFri, 30 Nov 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-11-30:posts/2012/novembre/30/filename_metadata-example/Second articlehttp://blog.notmyidea.org/posts/2012/f%C3%A9vrier/29/second-article/<p>This is some article, in english</p> +Alexis MétaireauWed, 29 Feb 2012 00:00:00 +0100tag:blog.notmyidea.org,2012-02-29:posts/2012/février/29/second-article/foobarbazUnbelievable !http://blog.notmyidea.org/posts/2010/octobre/15/unbelievable/<p>Or completely awesome. Depends the needs.</p> +<p><a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a root-relative link to markdown-article</a> +<a class="reference external" href="http://blog.notmyidea.org/posts/2011/avril/20/a-markdown-powered-article/">a file-relative link to markdown-article</a></p> +<div class="section" id="testing-sourcecode-directive"> +<h2>Testing sourcecode directive</h2> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table></div> +<div class="section" id="testing-another-case"> +<h2>Testing another case</h2> +<p>This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.</p> +<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +</td></tr></table><p>Lovely.</p> +</div> +<div class="section" id="testing-more-sourcecode-directives"> +<h2>Testing more sourcecode directives</h2> +<div class="highlight"><pre><span id="foo-8"><a name="foo-8"></a><span class="lineno special"> 8</span> <span class="testingk">def</span> <span class="testingnf">run</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingp">):</span><br></span><span id="foo-9"><a name="foo-9"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">assert_has_content</span><span class="testingp">()</span><br></span><span id="foo-10"><a name="foo-10"></a><span class="lineno special">10</span> <span class="testingk">try</span><span class="testingp">:</span><br></span><span id="foo-11"><a name="foo-11"></a><span class="lineno"> </span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">get_lexer_by_name</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">arguments</span><span class="testingp">[</span><span class="testingmi">0</span><span class="testingp">])</span><br></span><span id="foo-12"><a name="foo-12"></a><span class="lineno special">12</span> <span class="testingk">except</span> <span class="testingne">ValueError</span><span class="testingp">:</span><br></span><span id="foo-13"><a name="foo-13"></a><span class="lineno"> </span> <span class="testingc"># no lexer found - use the text one instead of an exception</span><br></span><span id="foo-14"><a name="foo-14"></a><span class="lineno special">14</span> <span class="testingn">lexer</span> <span class="testingo">=</span> <span class="testingn">TextLexer</span><span class="testingp">()</span><br></span><span id="foo-15"><a name="foo-15"></a><span class="lineno"> </span> <br></span><span id="foo-16"><a name="foo-16"></a><span class="lineno special">16</span> <span class="testingk">if</span> <span class="testingp">(</span><span class="testings">&#39;linenos&#39;</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span> <span class="testingow">and</span><br></span><span id="foo-17"><a name="foo-17"></a><span class="lineno"> </span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingow">not</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;table&#39;</span><span class="testingp">,</span> <span class="testings">&#39;inline&#39;</span><span class="testingp">)):</span><br></span><span id="foo-18"><a name="foo-18"></a><span class="lineno special">18</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testings">&#39;linenos&#39;</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testings">&#39;table&#39;</span><br></span><span id="foo-19"><a name="foo-19"></a><span class="lineno"> </span> <br></span><span id="foo-20"><a name="foo-20"></a><span class="lineno special">20</span> <span class="testingk">for</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingp">(</span><span class="testings">&#39;nowrap&#39;</span><span class="testingp">,</span> <span class="testings">&#39;nobackground&#39;</span><span class="testingp">,</span> <span class="testings">&#39;anchorlinenos&#39;</span><span class="testingp">):</span><br></span><span id="foo-21"><a name="foo-21"></a><span class="lineno"> </span> <span class="testingk">if</span> <span class="testingn">flag</span> <span class="testingow">in</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">:</span><br></span><span id="foo-22"><a name="foo-22"></a><span class="lineno special">22</span> <span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">[</span><span class="testingn">flag</span><span class="testingp">]</span> <span class="testingo">=</span> <span class="testingbp">True</span><br></span><span id="foo-23"><a name="foo-23"></a><span class="lineno"> </span> <br></span><span id="foo-24"><a name="foo-24"></a><span class="lineno special">24</span> <span class="testingc"># noclasses should already default to False, but just in case...</span><br></span><span id="foo-25"><a name="foo-25"></a><span class="lineno"> </span> <span class="testingn">formatter</span> <span class="testingo">=</span> <span class="testingn">HtmlFormatter</span><span class="testingp">(</span><span class="testingn">noclasses</span><span class="testingo">=</span><span class="testingbp">False</span><span class="testingp">,</span> <span class="testingo">**</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">options</span><span class="testingp">)</span><br></span><span id="foo-26"><a name="foo-26"></a><span class="lineno special">26</span> <span class="testingn">parsed</span> <span class="testingo">=</span> <span class="testingn">highlight</span><span class="testingp">(</span><span class="testings">&#39;</span><span class="testingse">\n</span><span class="testings">&#39;</span><span class="testingo">.</span><span class="testingn">join</span><span class="testingp">(</span><span class="testingbp">self</span><span class="testingo">.</span><span class="testingn">content</span><span class="testingp">),</span> <span class="testingn">lexer</span><span class="testingp">,</span> <span class="testingn">formatter</span><span class="testingp">)</span><br></span><span id="foo-27"><a name="foo-27"></a><span class="lineno"> </span> <span class="testingk">return</span> <span class="testingp">[</span><span class="testingn">nodes</span><span class="testingo">.</span><span class="testingn">raw</span><span class="testingp">(</span><span class="testings">&#39;&#39;</span><span class="testingp">,</span> <span class="testingn">parsed</span><span class="testingp">,</span> <span class="testingn">format</span><span class="testingo">=</span><span class="testings">&#39;html&#39;</span><span class="testingp">)]</span><br></span></pre></div> +<p>Lovely.</p> +</div> +<div class="section" id="testing-even-more-sourcecode-directives"> +<h2>Testing even more sourcecode directives</h2> +<span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +<p>Lovely.</p> +</div> +<div class="section" id="testing-overriding-config-defaults"> +<h2>Testing overriding config defaults</h2> +<p>Even if the default is line numbers, we can override it here</p> +<div class="highlight"><pre><span class="n">formatter</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">options</span> <span class="ow">and</span> <span class="n">VARIANTS</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">keys</span><span class="p">()[</span><span class="mi">0</span><span class="p">]]</span> +</pre></div> +<p>Lovely.</p> +</div> +Alexis MétaireauFri, 15 Oct 2010 20:30:00 +0200tag:blog.notmyidea.org,2010-10-15:posts/2010/octobre/15/unbelievable/The baz taghttp://blog.notmyidea.org/tag/baz.html<p>This article overrides the listening of the articles under the <em>baz</em> tag.</p> +Alexis MétaireauSun, 14 Mar 2010 00:00:00 +0100tag:blog.notmyidea.org,2010-03-14:tag/baz.html \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/yeah.atom.xml b/pelican/tests/output/custom_locale/feeds/yeah.atom.xml new file mode 100644 index 00000000..a8dbb270 --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/yeah.atom.xml @@ -0,0 +1,14 @@ + +Alexis' loghttp://blog.notmyidea.org/2013-11-17T23:29:00+01:00This is a super article !2013-11-17T23:29:00+01:00Alexis Métaireautag:blog.notmyidea.org,2010-12-02:posts/2010/décembre/02/this-is-a-super-article/<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/feeds/yeah.rss.xml b/pelican/tests/output/custom_locale/feeds/yeah.rss.xml new file mode 100644 index 00000000..379d1b93 --- /dev/null +++ b/pelican/tests/output/custom_locale/feeds/yeah.rss.xml @@ -0,0 +1,14 @@ + +Alexis' loghttp://blog.notmyidea.org/Sun, 17 Nov 2013 23:29:00 +0100This is a super article !http://blog.notmyidea.org/posts/2010/d%C3%A9cembre/02/this-is-a-super-article/<p>Some content here !</p> +<div class="section" id="this-is-a-simple-title"> +<h2>This is a simple title</h2> +<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /> +<img alt="alternate text" src="http://blog.notmyidea.org/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /> +<pre class="literal-block"> +&gt;&gt;&gt; from ipdb import set_trace +&gt;&gt;&gt; set_trace() +</pre> +<p>→ And now try with some utf8 hell: ééé</p> +</div> +Alexis MétaireauSun, 17 Nov 2013 23:29:00 +0100tag:blog.notmyidea.org,2010-12-02:posts/2010/décembre/02/this-is-a-super-article/foobarfoobar \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/index.html b/pelican/tests/output/custom_locale/index.html new file mode 100644 index 00000000..d64bea7d --- /dev/null +++ b/pelican/tests/output/custom_locale/index.html @@ -0,0 +1,173 @@ + + + + + Alexis' log + + + + + + + + + +Fork me on GitHub + + + + +
    +

    Other articles

    +
    +
      + +
    1. + +
    2. + +
    3. +
    +

    + Page 1 / 3 + » +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/index2.html b/pelican/tests/output/custom_locale/index2.html new file mode 100644 index 00000000..3b3d2d52 --- /dev/null +++ b/pelican/tests/output/custom_locale/index2.html @@ -0,0 +1,187 @@ + + + + + Alexis' log + + + + + + + + + +Fork me on GitHub + + + +
    +
      +
    1. + +
    2. + +
    3. + +
    4. +
      +

      Oh yeah !

      +
      + +
      +
      +

      Why not ?

      +

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !

      +alternate text +
      + + read more +

      There are comments.

      +
    5. +
    +

    + « + Page 2 / 3 + » +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/pelican/tests/output/custom_locale/index3.html b/pelican/tests/output/custom_locale/index3.html new file mode 100644 index 00000000..96d70261 --- /dev/null +++ b/pelican/tests/output/custom_locale/index3.html @@ -0,0 +1,138 @@ + + + + + Alexis' log + + + + + + + + + +Fork me on GitHub + + + +
    +
      +
    1. + +
    2. +
    +

    + « + Page 3 / 3 +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/jinja2_template.html b/pelican/tests/output/custom_locale/jinja2_template.html new file mode 100644 index 00000000..0eafa913 --- /dev/null +++ b/pelican/tests/output/custom_locale/jinja2_template.html @@ -0,0 +1,77 @@ + + + + + Alexis' log + + + + + + + + + +Fork me on GitHub + + + +Some text + +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/oh-yeah-fr.html b/pelican/tests/output/custom_locale/oh-yeah-fr.html new file mode 100644 index 00000000..77d9e2c5 --- /dev/null +++ b/pelican/tests/output/custom_locale/oh-yeah-fr.html @@ -0,0 +1,116 @@ + + + + + Trop bien ! + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + Trop bien !

    +
    + +
    +

    Et voila du contenu en français

    + +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/override/index.html b/pelican/tests/output/custom_locale/override/index.html new file mode 100644 index 00000000..e84d79fe --- /dev/null +++ b/pelican/tests/output/custom_locale/override/index.html @@ -0,0 +1,81 @@ + + + + + Override url/save_as + + + + + + + + + +Fork me on GitHub + + +
    +

    Override url/save_as

    + +

    Test page which overrides save_as and url so that this page will be generated +at a custom location.

    + +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/pages/this-is-a-test-hidden-page.html b/pelican/tests/output/custom_locale/pages/this-is-a-test-hidden-page.html new file mode 100644 index 00000000..dced8107 --- /dev/null +++ b/pelican/tests/output/custom_locale/pages/this-is-a-test-hidden-page.html @@ -0,0 +1,81 @@ + + + + + This is a test hidden page + + + + + + + + + +Fork me on GitHub + + +
    +

    This is a test hidden page

    + +

    This is great for things like error(404) pages +Anyone can see this page but it's not linked to anywhere!

    + +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/pages/this-is-a-test-page.html b/pelican/tests/output/custom_locale/pages/this-is-a-test-page.html new file mode 100644 index 00000000..46ea4fef --- /dev/null +++ b/pelican/tests/output/custom_locale/pages/this-is-a-test-page.html @@ -0,0 +1,81 @@ + + + + + This is a test page + + + + + + + + + +Fork me on GitHub + + +
    +

    This is a test page

    + +

    Just an image.

    +alternate text + +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/pictures/Fat_Cat.jpg b/pelican/tests/output/custom_locale/pictures/Fat_Cat.jpg new file mode 100644 index 00000000..d8a96d35 Binary files /dev/null and b/pelican/tests/output/custom_locale/pictures/Fat_Cat.jpg differ diff --git a/pelican/tests/output/custom_locale/pictures/Sushi.jpg b/pelican/tests/output/custom_locale/pictures/Sushi.jpg new file mode 100644 index 00000000..e49e5f0a Binary files /dev/null and b/pelican/tests/output/custom_locale/pictures/Sushi.jpg differ diff --git a/pelican/tests/output/custom_locale/pictures/Sushi_Macro.jpg b/pelican/tests/output/custom_locale/pictures/Sushi_Macro.jpg new file mode 100644 index 00000000..21f935a1 Binary files /dev/null and b/pelican/tests/output/custom_locale/pictures/Sushi_Macro.jpg differ diff --git a/pelican/tests/output/custom_locale/posts/2010/décembre/02/this-is-a-super-article/index.html b/pelican/tests/output/custom_locale/posts/2010/décembre/02/this-is-a-super-article/index.html new file mode 100644 index 00000000..b2ffdf9c --- /dev/null +++ b/pelican/tests/output/custom_locale/posts/2010/décembre/02/this-is-a-super-article/index.html @@ -0,0 +1,129 @@ + + + + + This is a super article ! + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + This is a super article !

    +
    + +
    +

    Some content here !

    +
    +

    This is a simple title

    +

    And here comes the cool stuff.

    +alternate text +alternate text +
    +>>> from ipdb import set_trace
    +>>> set_trace()
    +
    +

    → And now try with some utf8 hell: ééé

    +
    + +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/pelican/tests/output/custom_locale/posts/2010/octobre/15/unbelievable/index.html b/pelican/tests/output/custom_locale/posts/2010/octobre/15/unbelievable/index.html new file mode 100644 index 00000000..d7449ebf --- /dev/null +++ b/pelican/tests/output/custom_locale/posts/2010/octobre/15/unbelievable/index.html @@ -0,0 +1,146 @@ + + + + + Unbelievable ! + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + Unbelievable !

    +
    + +
    +

    Or completely awesome. Depends the needs.

    +

    a root-relative link to markdown-article +a file-relative link to markdown-article

    +
    +

    Testing sourcecode directive

    +
    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    +
    +
    +
    +

    Testing another case

    +

    This will now have a line number in 'custom' since it's the default in +pelican.conf, it will have nothing in default.

    +
    1
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    +
    +

    Lovely.

    +
    +
    +

    Testing more sourcecode directives

    +
     8 def run(self):
    self.assert_has_content()
    10 try:
    lexer = get_lexer_by_name(self.arguments[0])
    12 except ValueError:
    # no lexer found - use the text one instead of an exception
    14 lexer = TextLexer()

    16 if ('linenos' in self.options and
    self.options['linenos'] not in ('table', 'inline')):
    18 self.options['linenos'] = 'table'

    20 for flag in ('nowrap', 'nobackground', 'anchorlinenos'):
    if flag in self.options:
    22 self.options[flag] = True

    24 # noclasses should already default to False, but just in case...
    formatter = HtmlFormatter(noclasses=False, **self.options)
    26 parsed = highlight('\n'.join(self.content), lexer, formatter)
    return [nodes.raw('', parsed, format='html')]
    +

    Lovely.

    +
    +
    +

    Testing even more sourcecode directives

    +formatter = self.options and VARIANTS[self.options.keys()[0]] +

    Lovely.

    +
    +
    +

    Testing overriding config defaults

    +

    Even if the default is line numbers, we can override it here

    +
    formatter = self.options and VARIANTS[self.options.keys()[0]]
    +
    +

    Lovely.

    +
    + +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/posts/2010/octobre/20/oh-yeah/index.html b/pelican/tests/output/custom_locale/posts/2010/octobre/20/oh-yeah/index.html new file mode 100644 index 00000000..12c67404 --- /dev/null +++ b/pelican/tests/output/custom_locale/posts/2010/octobre/20/oh-yeah/index.html @@ -0,0 +1,121 @@ + + + + + Oh yeah ! + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + Oh yeah !

    +
    + +
    +
    +

    Why not ?

    +

    After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !

    +alternate text +
    + +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/posts/2011/avril/20/a-markdown-powered-article/index.html b/pelican/tests/output/custom_locale/posts/2011/avril/20/a-markdown-powered-article/index.html new file mode 100644 index 00000000..81bb6fa6 --- /dev/null +++ b/pelican/tests/output/custom_locale/posts/2011/avril/20/a-markdown-powered-article/index.html @@ -0,0 +1,115 @@ + + + + + A markdown powered article + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + A markdown powered article

    +
    + +
    +

    You're mutually oblivious.

    +

    a root-relative link to unbelievable +a file-relative link to unbelievable

    +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/posts/2011/février/17/article-1/index.html b/pelican/tests/output/custom_locale/posts/2011/février/17/article-1/index.html new file mode 100644 index 00000000..8aa9de4a --- /dev/null +++ b/pelican/tests/output/custom_locale/posts/2011/février/17/article-1/index.html @@ -0,0 +1,114 @@ + + + + + Article 1 + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + Article 1

    +
    + +
    +

    Article 1

    + +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/posts/2011/février/17/article-2/index.html b/pelican/tests/output/custom_locale/posts/2011/février/17/article-2/index.html new file mode 100644 index 00000000..1d78ade5 --- /dev/null +++ b/pelican/tests/output/custom_locale/posts/2011/février/17/article-2/index.html @@ -0,0 +1,114 @@ + + + + + Article 2 + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + Article 2

    +
    + +
    +

    Article 2

    + +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/posts/2011/février/17/article-3/index.html b/pelican/tests/output/custom_locale/posts/2011/février/17/article-3/index.html new file mode 100644 index 00000000..372090cc --- /dev/null +++ b/pelican/tests/output/custom_locale/posts/2011/février/17/article-3/index.html @@ -0,0 +1,114 @@ + + + + + Article 3 + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + Article 3

    +
    + +
    +

    Article 3

    + +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/posts/2012/février/29/second-article/index.html b/pelican/tests/output/custom_locale/posts/2012/février/29/second-article/index.html new file mode 100644 index 00000000..812fdfd0 --- /dev/null +++ b/pelican/tests/output/custom_locale/posts/2012/février/29/second-article/index.html @@ -0,0 +1,116 @@ + + + + + Second article + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + Second article

    +
    + +
    +

    This is some article, in english

    + +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/posts/2012/novembre/30/filename_metadata-example/index.html b/pelican/tests/output/custom_locale/posts/2012/novembre/30/filename_metadata-example/index.html new file mode 100644 index 00000000..de426279 --- /dev/null +++ b/pelican/tests/output/custom_locale/posts/2012/novembre/30/filename_metadata-example/index.html @@ -0,0 +1,114 @@ + + + + + FILENAME_METADATA example + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + FILENAME_METADATA example

    +
    + +
    +

    Some cool stuff!

    + +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/robots.txt b/pelican/tests/output/custom_locale/robots.txt new file mode 100644 index 00000000..19a6e299 --- /dev/null +++ b/pelican/tests/output/custom_locale/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: /pictures diff --git a/pelican/tests/output/custom_locale/second-article-fr.html b/pelican/tests/output/custom_locale/second-article-fr.html new file mode 100644 index 00000000..07a2a09c --- /dev/null +++ b/pelican/tests/output/custom_locale/second-article-fr.html @@ -0,0 +1,116 @@ + + + + + Deuxième article + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + Deuxième article

    +
    + +
    +

    Ceci est un article, en français.

    + +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/tag/bar.html b/pelican/tests/output/custom_locale/tag/bar.html new file mode 100644 index 00000000..911f53af --- /dev/null +++ b/pelican/tests/output/custom_locale/tag/bar.html @@ -0,0 +1,160 @@ + + + + + Alexis' log - bar + + + + + + + + + +Fork me on GitHub + + + + +
    +

    Other articles

    +
    +
      + +
    1. + +
    2. +
      +

      Oh yeah !

      +
      + +
      +
      +

      Why not ?

      +

      After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH !

      +alternate text +
      + + read more +

      There are comments.

      +
    3. +
    +

    + Page 1 / 1 +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/pelican/tests/output/custom_locale/tag/baz.html b/pelican/tests/output/custom_locale/tag/baz.html new file mode 100644 index 00000000..1cea44d1 --- /dev/null +++ b/pelican/tests/output/custom_locale/tag/baz.html @@ -0,0 +1,114 @@ + + + + + The baz tag + + + + + + + + + +Fork me on GitHub + + +
    +
    +
    +

    + The baz tag

    +
    + +
    +

    This article overrides the listening of the articles under the baz tag.

    + +
    +
    +

    Comments !

    +
    + + +
    + +
    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/tag/foo.html b/pelican/tests/output/custom_locale/tag/foo.html new file mode 100644 index 00000000..01bb8b17 --- /dev/null +++ b/pelican/tests/output/custom_locale/tag/foo.html @@ -0,0 +1,130 @@ + + + + + Alexis' log - foo + + + + + + + + + +Fork me on GitHub + + + + +
    +

    Other articles

    +
    +
      + +
    1. +
    +

    + Page 1 / 1 +

    +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/pelican/tests/output/custom_locale/tag/foobar.html b/pelican/tests/output/custom_locale/tag/foobar.html new file mode 100644 index 00000000..85b2b0ed --- /dev/null +++ b/pelican/tests/output/custom_locale/tag/foobar.html @@ -0,0 +1,109 @@ + + + + + Alexis' log - foobar + + + + + + + + + +Fork me on GitHub + + + + +
    +
    +

    blogroll

    + +
    + +
    + + + + + + diff --git a/pelican/tests/output/custom_locale/tag/oh.html b/pelican/tests/output/custom_locale/tag/oh.html new file mode 100644 index 00000000..21c8e352 --- /dev/null +++ b/pelican/tests/output/custom_locale/tag/oh.html @@ -0,0 +1,80 @@ + + + + + Oh Oh Oh + + + + + + + + + +Fork me on GitHub + + +
    +

    Oh Oh Oh

    + +

    This page overrides the listening of the articles under the oh tag.

    + +
    +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/tests/output/custom/tag/yeah.html b/pelican/tests/output/custom_locale/tag/yeah.html similarity index 57% rename from tests/output/custom/tag/yeah.html rename to pelican/tests/output/custom_locale/tag/yeah.html index bfd7b4cd..45789e86 100644 --- a/tests/output/custom/tag/yeah.html +++ b/pelican/tests/output/custom_locale/tag/yeah.html @@ -1,153 +1,83 @@ - Alexis' log - yeah - - + Alexis' log - yeah + - - - - - - - - + + - - Fork me on GitHub - - - - - - - - - - - - - - - - - -
    - - - -
    - - - - \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/tags.html b/pelican/tests/output/custom_locale/tags.html new file mode 100644 index 00000000..0da0d291 --- /dev/null +++ b/pelican/tests/output/custom_locale/tags.html @@ -0,0 +1,87 @@ + + + + + Alexis' log - Tags + + + + + + + + + +Fork me on GitHub + + + +
    +

    Tags for Alexis' log

    + +
    + +
    +
    +

    blogroll

    + +
    + +
    + + + + + + \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/theme/css/main.css b/pelican/tests/output/custom_locale/theme/css/main.css new file mode 100644 index 00000000..2efb518d --- /dev/null +++ b/pelican/tests/output/custom_locale/theme/css/main.css @@ -0,0 +1,451 @@ +/* + Name: Smashing HTML5 + Date: July 2009 + Description: Sample layout for HTML5 and CSS3 goodness. + Version: 1.0 + License: MIT + Licensed by: Smashing Media GmbH + Original author: Enrique Ramírez +*/ + +/* Imports */ +@import url("reset.css"); +@import url("pygment.css"); +@import url("typogrify.css"); +@import url(//fonts.googleapis.com/css?family=Yanone+Kaffeesatz&subset=latin); + +/***** Global *****/ +/* Body */ +body { + background: #F5F4EF; + color: #000305; + font-size: 87.5%; /* Base font size: 14px */ + font-family: 'Trebuchet MS', Trebuchet, 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; + line-height: 1.429; + margin: 0; + padding: 0; + text-align: left; +} + +/* Headings */ +h1 {font-size: 2em } +h2 {font-size: 1.571em} /* 22px */ +h3 {font-size: 1.429em} /* 20px */ +h4 {font-size: 1.286em} /* 18px */ +h5 {font-size: 1.143em} /* 16px */ +h6 {font-size: 1em} /* 14px */ + +h1, h2, h3, h4, h5, h6 { + font-weight: 400; + line-height: 1.1; + margin-bottom: .8em; + font-family: 'Yanone Kaffeesatz', arial, serif; +} + +h3, h4, h5, h6 { margin-top: .8em; } + +hr { border: 2px solid #EEEEEE; } + +/* Anchors */ +a {outline: 0;} +a img {border: 0px; text-decoration: none;} +a:link, a:visited { + color: #C74350; + padding: 0 1px; + text-decoration: underline; +} +a:hover, a:active { + background-color: #C74350; + color: #fff; + text-decoration: none; + text-shadow: 1px 1px 1px #333; +} + +h1 a:hover { + background-color: inherit +} + +/* Paragraphs */ +div.line-block, +p { margin-top: 1em; + margin-bottom: 1em;} + +strong, b {font-weight: bold;} +em, i {font-style: italic;} + +/* Lists */ +ul { + list-style: outside disc; + margin: 0em 0 0 1.5em; +} + +ol { + list-style: outside decimal; + margin: 0em 0 0 1.5em; +} + +li { margin-top: 0.5em;} + +.post-info { + float:right; + margin:10px; + padding:5px; +} + +.post-info p{ + margin-top: 1px; + margin-bottom: 1px; +} + +.readmore { float: right } + +dl {margin: 0 0 1.5em 0;} +dt {font-weight: bold;} +dd {margin-left: 1.5em;} + +pre{background-color: rgb(238, 238, 238); padding: 10px; margin: 10px; overflow: auto;} + +/* Quotes */ +blockquote { + margin: 20px; + font-style: italic; +} +cite {} + +q {} + +div.note { + float: right; + margin: 5px; + font-size: 85%; + max-width: 300px; +} + +/* Tables */ +table {margin: .5em auto 1.5em auto; width: 98%;} + + /* Thead */ + thead th {padding: .5em .4em; text-align: left;} + thead td {} + + /* Tbody */ + tbody td {padding: .5em .4em;} + tbody th {} + + tbody .alt td {} + tbody .alt th {} + + /* Tfoot */ + tfoot th {} + tfoot td {} + +/* HTML5 tags */ +header, section, footer, +aside, nav, article, figure { + display: block; +} + +/***** Layout *****/ +.body {clear: both; margin: 0 auto; width: 800px;} +img.right, figure.right {float: right; margin: 0 0 2em 2em;} +img.left, figure.left {float: left; margin: 0 2em 2em 0;} + +/* + Header +*****************/ +#banner { + margin: 0 auto; + padding: 2.5em 0 0 0; +} + + /* Banner */ + #banner h1 {font-size: 3.571em; line-height: 0;} + #banner h1 a:link, #banner h1 a:visited { + color: #000305; + display: block; + font-weight: bold; + margin: 0 0 .6em .2em; + text-decoration: none; + } + #banner h1 a:hover, #banner h1 a:active { + background: none; + color: #C74350; + text-shadow: none; + } + + #banner h1 strong {font-size: 0.36em; font-weight: normal;} + + /* Main Nav */ + #banner nav { + background: #000305; + font-size: 1.143em; + height: 40px; + line-height: 30px; + margin: 0 auto 2em auto; + padding: 0; + text-align: center; + width: 800px; + + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + } + + #banner nav ul {list-style: none; margin: 0 auto; width: 800px;} + #banner nav li {float: left; display: inline; margin: 0;} + + #banner nav a:link, #banner nav a:visited { + color: #fff; + display: inline-block; + height: 30px; + padding: 5px 1.5em; + text-decoration: none; + } + #banner nav a:hover, #banner nav a:active, + #banner nav .active a:link, #banner nav .active a:visited { + background: #C74451; + color: #fff; + text-shadow: none !important; + } + + #banner nav li:first-child a { + border-top-left-radius: 5px; + -moz-border-radius-topleft: 5px; + -webkit-border-top-left-radius: 5px; + + border-bottom-left-radius: 5px; + -moz-border-radius-bottomleft: 5px; + -webkit-border-bottom-left-radius: 5px; + } + +/* + Featured +*****************/ +#featured { + background: #fff; + margin-bottom: 2em; + overflow: hidden; + padding: 20px; + width: 760px; + + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; +} + +#featured figure { + border: 2px solid #eee; + float: right; + margin: 0.786em 2em 0 5em; + width: 248px; +} +#featured figure img {display: block; float: right;} + +#featured h2 {color: #C74451; font-size: 1.714em; margin-bottom: 0.333em;} +#featured h3 {font-size: 1.429em; margin-bottom: .5em;} + +#featured h3 a:link, #featured h3 a:visited {color: #000305; text-decoration: none;} +#featured h3 a:hover, #featured h3 a:active {color: #fff;} + +/* + Body +*****************/ +#content { + background: #fff; + margin-bottom: 2em; + overflow: hidden; + padding: 20px 20px; + width: 760px; + + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; +} + +/* + Extras +*****************/ +#extras {margin: 0 auto 3em auto; overflow: hidden;} + +#extras ul {list-style: none; margin: 0;} +#extras li {border-bottom: 1px solid #fff;} +#extras h2 { + color: #C74350; + font-size: 1.429em; + margin-bottom: .25em; + padding: 0 3px; +} + +#extras a:link, #extras a:visited { + color: #444; + display: block; + border-bottom: 1px solid #F4E3E3; + text-decoration: none; + padding: .3em .25em; +} + +#extras a:hover, #extras a:active {color: #fff;} + + /* Blogroll */ + #extras .blogroll { + float: left; + width: 615px; + } + + #extras .blogroll li {float: left; margin: 0 20px 0 0; width: 185px;} + + /* Social */ + #extras .social { + float: right; + width: 175px; + } + + #extras div[class='social'] a { + background-repeat: no-repeat; + background-position: 3px 6px; + padding-left: 25px; + } + + /* Icons */ + .social a[href*='about.me'] {background-image: url('../images/icons/aboutme.png');} + .social a[href*='bitbucket.org'] {background-image: url('../images/icons/bitbucket.png');} + .social a[href*='delicious.com'] {background-image: url('../images/icons/delicious.png');} + .social a[href*='digg.com'] {background-image: url('../images/icons/digg.png');} + .social a[href*='facebook.com'] {background-image: url('../images/icons/facebook.png');} + .social a[href*='gitorious.org'] {background-image: url('../images/icons/gitorious.png');} + .social a[href*='github.com'], + .social a[href*='git.io'] { + background-image: url('../images/icons/github.png'); + background-size: 16px 16px; + } + .social a[href*='gittip.com'] {background-image: url('../images/icons/gittip.png');} + .social a[href*='plus.google.com'] {background-image: url('../images/icons/google-plus.png');} + .social a[href*='groups.google.com'] {background-image: url('../images/icons/google-groups.png');} + .social a[href*='news.ycombinator.com'], + .social a[href*='hackernewsers.com'] {background-image: url('../images/icons/hackernews.png');} + .social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');} + .social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');} + .social a[href*='reddit.com'] {background-image: url('../images/icons/reddit.png');} + .social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('../images/icons/rss.png');} + .social a[href*='slideshare.net'] {background-image: url('../images/icons/slideshare.png');} + .social a[href*='speakerdeck.com'] {background-image: url('../images/icons/speakerdeck.png');} + .social a[href*='stackoverflow.com'] {background-image: url('../images/icons/stackoverflow.png');} + .social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');} + .social a[href*='vimeo.com'] {background-image: url('../images/icons/vimeo.png');} + .social a[href*='youtube.com'] {background-image: url('../images/icons/youtube.png');} + +/* + About +*****************/ +#about { + background: #fff; + font-style: normal; + margin-bottom: 2em; + overflow: hidden; + padding: 20px; + text-align: left; + width: 760px; + + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; +} + +#about .primary {float: left; width: 165px;} +#about .primary strong {color: #C64350; display: block; font-size: 1.286em;} +#about .photo {float: left; margin: 5px 20px;} + +#about .url:link, #about .url:visited {text-decoration: none;} + +#about .bio {float: right; width: 500px;} + +/* + Footer +*****************/ +#contentinfo {padding-bottom: 2em; text-align: right;} + +/***** Sections *****/ +/* Blog */ +.hentry { + display: block; + clear: both; + border-bottom: 1px solid #eee; + padding: 1.5em 0; +} +li:last-child .hentry, #content > .hentry {border: 0; margin: 0;} +#content > .hentry {padding: 1em 0;} +.hentry img{display : none ;} +.entry-title {font-size: 3em; margin-bottom: 10px; margin-top: 0;} +.entry-title a:link, .entry-title a:visited {text-decoration: none; color: #333;} +.entry-title a:visited {background-color: #fff;} + +.hentry .post-info * {font-style: normal;} + + /* Content */ + .hentry footer {margin-bottom: 2em;} + .hentry footer address {display: inline;} + #posts-list footer address {display: block;} + + /* Blog Index */ + #posts-list {list-style: none; margin: 0;} + #posts-list .hentry {padding-left: 10px; position: relative;} + + #posts-list footer { + left: 10px; + position: relative; + float: left; + top: 0.5em; + width: 190px; + } + + /* About the Author */ + #about-author { + background: #f9f9f9; + clear: both; + font-style: normal; + margin: 2em 0; + padding: 10px 20px 15px 20px; + + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + } + + #about-author strong { + color: #C64350; + clear: both; + display: block; + font-size: 1.429em; + } + + #about-author .photo {border: 1px solid #ddd; float: left; margin: 5px 1em 0 0;} + + /* Comments */ + #comments-list {list-style: none; margin: 0 1em;} + #comments-list blockquote { + background: #f8f8f8; + clear: both; + font-style: normal; + margin: 0; + padding: 15px 20px; + + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + } + #comments-list footer {color: #888; padding: .5em 1em 0 0; text-align: right;} + + #comments-list li:nth-child(2n) blockquote {background: #F5f5f5;} + + /* Add a Comment */ + #add-comment label {clear: left; float: left; text-align: left; width: 150px;} + #add-comment input[type='text'], + #add-comment input[type='email'], + #add-comment input[type='url'] {float: left; width: 200px;} + + #add-comment textarea {float: left; height: 150px; width: 495px;} + + #add-comment p.req {clear: both; margin: 0 .5em 1em 0; text-align: right;} + + #add-comment input[type='submit'] {float: right; margin: 0 .5em;} + #add-comment * {margin-bottom: .5em;} diff --git a/pelican/tests/output/custom_locale/theme/css/pygment.css b/pelican/tests/output/custom_locale/theme/css/pygment.css new file mode 100644 index 00000000..fdd056f6 --- /dev/null +++ b/pelican/tests/output/custom_locale/theme/css/pygment.css @@ -0,0 +1,205 @@ +.hll { +background-color:#eee; +} +.c { +color:#408090; +font-style:italic; +} +.err { +border:1px solid #FF0000; +} +.k { +color:#007020; +font-weight:bold; +} +.o { +color:#666666; +} +.cm { +color:#408090; +font-style:italic; +} +.cp { +color:#007020; +} +.c1 { +color:#408090; +font-style:italic; +} +.cs { +background-color:#FFF0F0; +color:#408090; +} +.gd { +color:#A00000; +} +.ge { +font-style:italic; +} +.gr { +color:#FF0000; +} +.gh { +color:#000080; +font-weight:bold; +} +.gi { +color:#00A000; +} +.go { +color:#303030; +} +.gp { +color:#C65D09; +font-weight:bold; +} +.gs { +font-weight:bold; +} +.gu { +color:#800080; +font-weight:bold; +} +.gt { +color:#0040D0; +} +.kc { +color:#007020; +font-weight:bold; +} +.kd { +color:#007020; +font-weight:bold; +} +.kn { +color:#007020; +font-weight:bold; +} +.kp { +color:#007020; +} +.kr { +color:#007020; +font-weight:bold; +} +.kt { +color:#902000; +} +.m { +color:#208050; +} +.s { +color:#4070A0; +} +.na { +color:#4070A0; +} +.nb { +color:#007020; +} +.nc { +color:#0E84B5; +font-weight:bold; +} +.no { +color:#60ADD5; +} +.nd { +color:#555555; +font-weight:bold; +} +.ni { +color:#D55537; +font-weight:bold; +} +.ne { +color:#007020; +} +.nf { +color:#06287E; +} +.nl { +color:#002070; +font-weight:bold; +} +.nn { +color:#0E84B5; +font-weight:bold; +} +.nt { +color:#062873; +font-weight:bold; +} +.nv { +color:#BB60D5; +} +.ow { +color:#007020; +font-weight:bold; +} +.w { +color:#BBBBBB; +} +.mf { +color:#208050; +} +.mh { +color:#208050; +} +.mi { +color:#208050; +} +.mo { +color:#208050; +} +.sb { +color:#4070A0; +} +.sc { +color:#4070A0; +} +.sd { +color:#4070A0; +font-style:italic; +} +.s2 { +color:#4070A0; +} +.se { +color:#4070A0; +font-weight:bold; +} +.sh { +color:#4070A0; +} +.si { +color:#70A0D0; +font-style:italic; +} +.sx { +color:#C65D09; +} +.sr { +color:#235388; +} +.s1 { +color:#4070A0; +} +.ss { +color:#517918; +} +.bp { +color:#007020; +} +.vc { +color:#BB60D5; +} +.vg { +color:#BB60D5; +} +.vi { +color:#BB60D5; +} +.il { +color:#208050; +} diff --git a/pelican/tests/output/custom_locale/theme/css/reset.css b/pelican/tests/output/custom_locale/theme/css/reset.css new file mode 100644 index 00000000..1e217566 --- /dev/null +++ b/pelican/tests/output/custom_locale/theme/css/reset.css @@ -0,0 +1,52 @@ +/* + Name: Reset Stylesheet + Description: Resets browser's default CSS + Author: Eric Meyer + Author URI: http://meyerweb.com/eric/tools/css/reset/ +*/ + +/* v1.0 | 20080212 */ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, font, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td { + background: transparent; + border: 0; + font-size: 100%; + margin: 0; + outline: 0; + padding: 0; + vertical-align: baseline; +} + +body {line-height: 1;} + +ol, ul {list-style: none;} + +blockquote, q {quotes: none;} + +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} + +/* remember to define focus styles! */ +:focus { + outline: 0; +} + +/* remember to highlight inserts somehow! */ +ins {text-decoration: none;} +del {text-decoration: line-through;} + +/* tables still need 'cellspacing="0"' in the markup */ +table { + border-collapse: collapse; + border-spacing: 0; +} \ No newline at end of file diff --git a/pelican/tests/output/custom_locale/theme/css/typogrify.css b/pelican/tests/output/custom_locale/theme/css/typogrify.css new file mode 100644 index 00000000..c9b34dc8 --- /dev/null +++ b/pelican/tests/output/custom_locale/theme/css/typogrify.css @@ -0,0 +1,3 @@ +.caps {font-size:.92em;} +.amp {color:#666; font-size:1.05em;font-family:"Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua",serif; font-style:italic;} +.dquo {margin-left:-.38em;} diff --git a/pelican/tests/output/custom_locale/theme/css/wide.css b/pelican/tests/output/custom_locale/theme/css/wide.css new file mode 100644 index 00000000..88fd59ce --- /dev/null +++ b/pelican/tests/output/custom_locale/theme/css/wide.css @@ -0,0 +1,48 @@ +@import url("main.css"); + +body { + font:1.3em/1.3 "Hoefler Text","Georgia",Georgia,serif,sans-serif; +} + +.post-info{ + display: none; +} + +#banner nav { + display: none; + -moz-border-radius: 0px; + margin-bottom: 20px; + overflow: hidden; + font-size: 1em; + background: #F5F4EF; +} + +#banner nav ul{ + padding-right: 50px; +} + +#banner nav li{ + float: right; + color: #000; +} + +#banner nav li a { + color: #000; +} + +#banner h1 { + margin-bottom: -18px; +} + +#featured, #extras { + padding: 50px; +} + +#featured { + padding-top: 20px; +} + +#extras { + padding-top: 0px; + padding-bottom: 0px; +} diff --git a/pelican/tests/output/custom_locale/theme/images/icons/aboutme.png b/pelican/tests/output/custom_locale/theme/images/icons/aboutme.png new file mode 100644 index 00000000..9609df3b Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/aboutme.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/bitbucket.png b/pelican/tests/output/custom_locale/theme/images/icons/bitbucket.png new file mode 100644 index 00000000..d05ba161 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/bitbucket.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/delicious.png b/pelican/tests/output/custom_locale/theme/images/icons/delicious.png new file mode 100644 index 00000000..3dccdd84 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/delicious.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/facebook.png b/pelican/tests/output/custom_locale/theme/images/icons/facebook.png new file mode 100644 index 00000000..74e7ad52 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/facebook.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/github.png b/pelican/tests/output/custom_locale/theme/images/icons/github.png new file mode 100644 index 00000000..8b25551a Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/github.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/gitorious.png b/pelican/tests/output/custom_locale/theme/images/icons/gitorious.png new file mode 100644 index 00000000..3eeb3ece Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/gitorious.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/gittip.png b/pelican/tests/output/custom_locale/theme/images/icons/gittip.png new file mode 100644 index 00000000..af949625 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/gittip.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/google-groups.png b/pelican/tests/output/custom_locale/theme/images/icons/google-groups.png new file mode 100644 index 00000000..5de15e68 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/google-groups.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/google-plus.png b/pelican/tests/output/custom_locale/theme/images/icons/google-plus.png new file mode 100644 index 00000000..3c6b7432 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/google-plus.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/hackernews.png b/pelican/tests/output/custom_locale/theme/images/icons/hackernews.png new file mode 100644 index 00000000..fc7a82d4 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/hackernews.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/lastfm.png b/pelican/tests/output/custom_locale/theme/images/icons/lastfm.png new file mode 100644 index 00000000..3a6c6262 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/lastfm.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/linkedin.png b/pelican/tests/output/custom_locale/theme/images/icons/linkedin.png new file mode 100644 index 00000000..d29c1201 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/linkedin.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/reddit.png b/pelican/tests/output/custom_locale/theme/images/icons/reddit.png new file mode 100644 index 00000000..71ae1215 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/reddit.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/rss.png b/pelican/tests/output/custom_locale/theme/images/icons/rss.png new file mode 100644 index 00000000..7862c65a Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/rss.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/slideshare.png b/pelican/tests/output/custom_locale/theme/images/icons/slideshare.png new file mode 100644 index 00000000..ecc97410 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/slideshare.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/speakerdeck.png b/pelican/tests/output/custom_locale/theme/images/icons/speakerdeck.png new file mode 100644 index 00000000..087d0931 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/speakerdeck.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/stackoverflow.png b/pelican/tests/output/custom_locale/theme/images/icons/stackoverflow.png new file mode 100644 index 00000000..f5b65e99 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/stackoverflow.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/twitter.png b/pelican/tests/output/custom_locale/theme/images/icons/twitter.png new file mode 100644 index 00000000..d0ef3cc1 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/twitter.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/vimeo.png b/pelican/tests/output/custom_locale/theme/images/icons/vimeo.png new file mode 100644 index 00000000..dba47202 Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/vimeo.png differ diff --git a/pelican/tests/output/custom_locale/theme/images/icons/youtube.png b/pelican/tests/output/custom_locale/theme/images/icons/youtube.png new file mode 100644 index 00000000..ce6cbe4f Binary files /dev/null and b/pelican/tests/output/custom_locale/theme/images/icons/youtube.png differ diff --git a/pelican/tests/support.py b/pelican/tests/support.py new file mode 100644 index 00000000..151fa3b6 --- /dev/null +++ b/pelican/tests/support.py @@ -0,0 +1,205 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function +__all__ = ['get_article', 'unittest', ] + +import os +import re +import subprocess +import sys +from six import StringIO +import logging +from logging.handlers import BufferingHandler +import unittest +import locale + +from functools import wraps +from contextlib import contextmanager +from tempfile import mkdtemp +from shutil import rmtree + +from pelican.contents import Article +from pelican.settings import DEFAULT_CONFIG + + +@contextmanager +def temporary_folder(): + """creates a temporary folder, return it and delete it afterwards. + + This allows to do something like this in tests: + + >>> with temporary_folder() as d: + # do whatever you want + """ + tempdir = mkdtemp() + try: + yield tempdir + finally: + rmtree(tempdir) + + +def isplit(s, sep=None): + """Behaves like str.split but returns a generator instead of a list. + + >>> list(isplit('\tUse the force\n')) == '\tUse the force\n'.split() + True + >>> list(isplit('\tUse the force\n')) == ['Use', 'the', 'force'] + True + >>> (list(isplit('\tUse the force\n', "e")) + == '\tUse the force\n'.split("e")) + True + >>> list(isplit('Use the force', "e")) == 'Use the force'.split("e") + True + >>> list(isplit('Use the force', "e")) == ['Us', ' th', ' forc', ''] + True + + """ + sep, hardsep = r'\s+' if sep is None else re.escape(sep), sep is not None + exp, pos, l = re.compile(sep), 0, len(s) + while True: + m = exp.search(s, pos) + if not m: + if pos < l or hardsep: + # ^ mimic "split()": ''.split() returns [] + yield s[pos:] + break + start = m.start() + if pos < start or hardsep: + # ^ mimic "split()": includes trailing empty string + yield s[pos:start] + pos = m.end() + + +def mute(returns_output=False): + """Decorate a function that prints to stdout, intercepting the output. + If "returns_output" is True, the function will return a generator + yielding the printed lines instead of the return values. + + The decorator literally hijack sys.stdout during each function + execution, so be careful with what you apply it to. + + >>> def numbers(): + print "42" + print "1984" + ... + >>> numbers() + 42 + 1984 + >>> mute()(numbers)() + >>> list(mute(True)(numbers)()) + ['42', '1984'] + + """ + + def decorator(func): + + @wraps(func) + def wrapper(*args, **kwargs): + + saved_stdout = sys.stdout + sys.stdout = StringIO() + + try: + out = func(*args, **kwargs) + if returns_output: + out = isplit(sys.stdout.getvalue().strip()) + finally: + sys.stdout = saved_stdout + + return out + + return wrapper + + 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: + metadata.update(extra_metadata) + return Article(content, metadata=metadata) + + +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`). + """ + + with open(os.devnull, 'w') as fnull: + try: + res = subprocess.call(executable, stdout=fnull, stderr=fnull) + except OSError: + res = None + + if res is None: + return unittest.skip('{0} executable not found'.format(executable)) + + return lambda func: func + + +def module_exists(module_name): + """Test if a module is importable.""" + + try: + __import__(module_name) + except ImportError: + return False + else: + return True + + +def locale_available(locale_): + old_locale = locale.setlocale(locale.LC_TIME) + + try: + locale.setlocale(locale.LC_TIME, str(locale_)) + except locale.Error: + return False + else: + locale.setlocale(locale.LC_TIME, old_locale) + return True + + +def get_settings(**kwargs): + """Provide tweaked setting dictionaries for testing + + Set keyword arguments to override specific settings. + """ + settings = DEFAULT_CONFIG.copy() + for key,value in kwargs.items(): + settings[key] = value + return settings + + +class LogCountHandler(BufferingHandler): + """Capturing and counting logged messages.""" + + def __init__(self, capacity=1000): + logging.handlers.BufferingHandler.__init__(self, capacity) + + def count_logs(self, msg=None, level=None): + return len([l for l in self.buffer + if (msg is None or re.match(msg, l.getMessage())) + and (level is None or l.levelno == level) + ]) + + +class LoggedTestCase(unittest.TestCase): + """A test case that captures log messages.""" + + def setUp(self): + super(LoggedTestCase, self).setUp() + self._logcount_handler = LogCountHandler() + logging.getLogger().addHandler(self._logcount_handler) + + def tearDown(self): + logging.getLogger().removeHandler(self._logcount_handler) + super(LoggedTestCase, self).tearDown() + + def assertLogCountEqual(self, count=None, msg=None, **kwargs): + actual = self._logcount_handler.count_logs(msg=msg, **kwargs) + self.assertEqual( + actual, count, + msg='expected {} occurrences of {!r}, but found {}'.format( + count, msg, actual)) diff --git a/pelican/tests/test_contents.py b/pelican/tests/test_contents.py new file mode 100644 index 00000000..01ee9ca2 --- /dev/null +++ b/pelican/tests/test_contents.py @@ -0,0 +1,571 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, absolute_import + +import six +from sys import platform +import locale +import os.path + +from pelican.tests.support import unittest, get_settings + +from pelican.contents import Page, Article, Static, URLWrapper +from pelican.settings import DEFAULT_CONFIG +from pelican.utils import path_to_url, truncate_html_words, SafeDatetime +from pelican.signals import content_object_init +from jinja2.utils import generate_lorem_ipsum + +# generate one paragraph, enclosed with

    +TEST_CONTENT = str(generate_lorem_ipsum(n=1)) +TEST_SUMMARY = generate_lorem_ipsum(n=1, html=False) + + +class TestPage(unittest.TestCase): + + def setUp(self): + super(TestPage, self).setUp() + self.old_locale = locale.setlocale(locale.LC_ALL) + locale.setlocale(locale.LC_ALL, str('C')) + self.page_kwargs = { + 'content': TEST_CONTENT, + 'context': { + 'localsiteurl': '', + }, + 'metadata': { + 'summary': TEST_SUMMARY, + 'title': 'foo bar', + 'author': 'Blogger', + }, + 'source_path': '/path/to/file/foo.ext' + } + + def tearDown(self): + locale.setlocale(locale.LC_ALL, self.old_locale) + + def test_use_args(self): + # Creating a page with arguments passed to the constructor should use + # them to initialise object's attributes. + metadata = {'foo': 'bar', 'foobar': 'baz', 'title': 'foobar', } + page = Page(TEST_CONTENT, metadata=metadata, + context={'localsiteurl': ''}) + for key, value in metadata.items(): + self.assertTrue(hasattr(page, key)) + self.assertEqual(value, getattr(page, key)) + self.assertEqual(page.content, TEST_CONTENT) + + def test_mandatory_properties(self): + # If the title is not set, must throw an exception. + page = Page('content') + with self.assertRaises(NameError): + page.check_properties() + + page = Page('content', metadata={'title': 'foobar'}) + page.check_properties() + + def test_summary_from_metadata(self): + # If a :summary: metadata is given, it should be used + page = Page(**self.page_kwargs) + self.assertEqual(page.summary, TEST_SUMMARY) + + def test_summary_max_length(self): + # If a :SUMMARY_MAX_LENGTH: is set, and there is no other summary, + # generated summary should not exceed the given length. + page_kwargs = self._copy_page_kwargs() + settings = get_settings() + page_kwargs['settings'] = settings + del page_kwargs['metadata']['summary'] + settings['SUMMARY_MAX_LENGTH'] = None + page = Page(**page_kwargs) + self.assertEqual(page.summary, TEST_CONTENT) + settings['SUMMARY_MAX_LENGTH'] = 10 + page = Page(**page_kwargs) + self.assertEqual(page.summary, truncate_html_words(TEST_CONTENT, 10)) + settings['SUMMARY_MAX_LENGTH'] = 0 + page = Page(**page_kwargs) + self.assertEqual(page.summary, '') + + def test_slug(self): + page_kwargs = self._copy_page_kwargs() + settings = get_settings() + page_kwargs['settings'] = settings + settings['SLUGIFY_SOURCE'] = "title" + page = Page(**page_kwargs) + self.assertEqual(page.slug, 'foo-bar') + settings['SLUGIFY_SOURCE'] = "basename" + page = Page(**page_kwargs) + self.assertEqual(page.slug, 'foo') + + def test_defaultlang(self): + # If no lang is given, default to the default one. + page = Page(**self.page_kwargs) + self.assertEqual(page.lang, DEFAULT_CONFIG['DEFAULT_LANG']) + + # it is possible to specify the lang in the metadata infos + self.page_kwargs['metadata'].update({'lang': 'fr', }) + page = Page(**self.page_kwargs) + self.assertEqual(page.lang, 'fr') + + def test_save_as(self): + # If a lang is not the default lang, save_as should be set + # accordingly. + + # if a title is defined, save_as should be set + page = Page(**self.page_kwargs) + 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, "pages/foo-bar-fr.html") + + def test_metadata_url_format(self): + # Arbitrary metadata should be passed through url_format() + page = Page(**self.page_kwargs) + self.assertIn('summary', page.url_format.keys()) + page.metadata['directory'] = 'test-dir' + page.settings = get_settings(PAGE_SAVE_AS='{directory}/{slug}') + self.assertEqual(page.save_as, 'test-dir/foo-bar') + + def test_datetime(self): + # If DATETIME is set to a tuple, it should be used to override LOCALE + dt = SafeDatetime(2015, 9, 13) + + page_kwargs = self._copy_page_kwargs() + + # set its date to dt + page_kwargs['metadata']['date'] = dt + page = Page(**page_kwargs) + + # page.locale_date is a unicode string in both python2 and python3 + dt_date = dt.strftime(DEFAULT_CONFIG['DEFAULT_DATE_FORMAT']) + # dt_date is a byte string in python2, and a unicode string in python3 + # Let's make sure it is a unicode string (relies on python 3.3 supporting the u prefix) + if type(dt_date) != type(u''): + # python2: + dt_date = unicode(dt_date, 'utf8') + + self.assertEqual(page.locale_date, dt_date ) + page_kwargs['settings'] = get_settings() + + # I doubt this can work on all platforms ... + if platform == "win32": + locale = 'jpn' + else: + locale = 'ja_JP.utf8' + page_kwargs['settings']['DATE_FORMATS'] = {'jp': (locale, + '%Y-%m-%d(%a)')} + page_kwargs['metadata']['lang'] = 'jp' + + import locale as locale_module + try: + page = Page(**page_kwargs) + self.assertEqual(page.locale_date, '2015-09-13(\u65e5)') + except locale_module.Error: + # The constructor of ``Page`` will try to set the locale to + # ``ja_JP.utf8``. But this attempt will failed when there is no + # such locale in the system. You can see which locales there are + # in your system with ``locale -a`` command. + # + # Until we find some other method to test this functionality, we + # will simply skip this test. + unittest.skip("There is no locale %s in this system." % locale) + + def test_template(self): + # Pages default to page, metadata overwrites + default_page = Page(**self.page_kwargs) + self.assertEqual('page', default_page.template) + page_kwargs = self._copy_page_kwargs() + page_kwargs['metadata']['template'] = 'custom' + custom_page = Page(**page_kwargs) + self.assertEqual('custom', custom_page.template) + + def _copy_page_kwargs(self): + # make a deep copy of page_kwargs + page_kwargs = dict([(key, self.page_kwargs[key]) for key in + self.page_kwargs]) + for key in page_kwargs: + if not isinstance(page_kwargs[key], dict): + break + page_kwargs[key] = dict([(subkey, page_kwargs[key][subkey]) + for subkey in page_kwargs[key]]) + + return page_kwargs + + def test_signal(self): + # If a title is given, it should be used to generate the slug. + + def receiver_test_function(sender, instance): + pass + + content_object_init.connect(receiver_test_function, sender=Page) + Page(**self.page_kwargs) + self.assertTrue(content_object_init.has_receivers_for(Page)) + + def test_get_content(self): + # Test that the content is updated with the relative links to + # filenames, tags and categories. + settings = get_settings() + args = self.page_kwargs.copy() + args['settings'] = settings + + # Tag + args['content'] = ('A simple test, with a ' + 'link') + page = Page(**args) + content = page.get_content('http://notmyidea.org') + self.assertEqual(content, ('A simple test, with a ' + 'link')) + + # Category + args['content'] = ('A simple test, with a ' + 'link') + page = Page(**args) + content = page.get_content('http://notmyidea.org') + self.assertEqual(content, + ('A simple test, with a ' + 'link')) + + def test_intrasite_link(self): + # type does not take unicode in PY2 and bytes in PY3, which in + # combination with unicode literals leads to following insane line: + cls_name = '_DummyArticle' if six.PY3 else b'_DummyArticle' + article = type(cls_name, (object,), {'url': 'article.html'}) + + args = self.page_kwargs.copy() + args['settings'] = get_settings() + args['source_path'] = 'content' + args['context']['filenames'] = {'article.rst': article} + + # Classic intrasite link via filename + args['content'] = ( + 'A simple test, with a ' + 'link' + ) + content = Page(**args).get_content('http://notmyidea.org') + self.assertEqual( + content, + 'A simple test, with a ' + 'link' + ) + + # fragment + args['content'] = ( + 'A simple test, with a ' + 'link' + ) + content = Page(**args).get_content('http://notmyidea.org') + self.assertEqual( + content, + 'A simple test, with a ' + 'link' + ) + + # query + args['content'] = ( + 'A simple test, with a ' + 'link' + ) + content = Page(**args).get_content('http://notmyidea.org') + self.assertEqual( + content, + 'A simple test, with a ' + 'link' + ) + + # combination + args['content'] = ( + 'A simple test, with a ' + 'link' + ) + content = Page(**args).get_content('http://notmyidea.org') + self.assertEqual( + content, + 'A simple test, with a ' + 'link' + ) + + def test_intrasite_link_more(self): + # type does not take unicode in PY2 and bytes in PY3, which in + # combination with unicode literals leads to following insane line: + cls_name = '_DummyAsset' if six.PY3 else b'_DummyAsset' + + args = self.page_kwargs.copy() + args['settings'] = get_settings() + args['source_path'] = 'content' + args['context']['filenames'] = { + 'images/poster.jpg': type(cls_name, (object,), {'url': 'images/poster.jpg'}), + 'assets/video.mp4': type(cls_name, (object,), {'url': 'assets/video.mp4'}), + 'images/graph.svg': type(cls_name, (object,), {'url': 'images/graph.svg'}), + 'reference.rst': type(cls_name, (object,), {'url': 'reference.html'}), + } + + # video.poster + args['content'] = ( + 'There is a video with poster ' + '' + ) + content = Page(**args).get_content('http://notmyidea.org') + self.assertEqual( + content, + 'There is a video with poster ' + '' + ) + + # object.data + args['content'] = ( + 'There is a svg object ' + '' + ) + content = Page(**args).get_content('http://notmyidea.org') + self.assertEqual( + content, + 'There is a svg object ' + '' + ) + + # blockquote.cite + args['content'] = ( + 'There is a blockquote with cite attribute ' + '

    blah blah
    ' + ) + content = Page(**args).get_content('http://notmyidea.org') + self.assertEqual( + content, + 'There is a blockquote with cite attribute ' + '
    blah blah
    ' + ) + + def test_intrasite_link_markdown_spaces(self): + # Markdown introduces %20 instead of spaces, this tests that + # we support markdown doing this. + cls_name = '_DummyArticle' if six.PY3 else b'_DummyArticle' + article = type(cls_name, (object,), {'url': 'article-spaces.html'}) + + args = self.page_kwargs.copy() + args['settings'] = get_settings() + args['source_path'] = 'content' + args['context']['filenames'] = {'article spaces.rst': article} + + # An intrasite link via filename with %20 as a space + args['content'] = ( + 'A simple test, with a ' + 'link' + ) + content = Page(**args).get_content('http://notmyidea.org') + self.assertEqual( + content, + 'A simple test, with a ' + 'link' + ) + + def test_multiple_authors(self): + """Test article with multiple authors.""" + args = self.page_kwargs.copy() + content = Page(**args) + assert content.authors == [content.author] + args['metadata'].pop('author') + args['metadata']['authors'] = ['First Author', 'Second Author'] + content = Page(**args) + assert content.authors + assert content.author == content.authors[0] + + +class TestArticle(TestPage): + def test_template(self): + # Articles default to article, metadata overwrites + default_article = Article(**self.page_kwargs) + self.assertEqual('article', default_article.template) + article_kwargs = self._copy_page_kwargs() + article_kwargs['metadata']['template'] = 'custom' + custom_article = Article(**article_kwargs) + self.assertEqual('custom', custom_article.template) + + def test_slugify_category_author(self): + settings = get_settings() + settings['SLUG_SUBSTITUTIONS'] = [ ('C#', 'csharp') ] + settings['ARTICLE_URL'] = '{author}/{category}/{slug}/' + settings['ARTICLE_SAVE_AS'] = '{author}/{category}/{slug}/index.html' + article_kwargs = self._copy_page_kwargs() + article_kwargs['metadata']['author'] = "O'Brien" + article_kwargs['metadata']['category'] = 'C# & stuff' + article_kwargs['metadata']['title'] = 'fnord' + article_kwargs['settings'] = settings + article = Article(**article_kwargs) + self.assertEqual(article.url, 'obrien/csharp-stuff/fnord/') + self.assertEqual(article.save_as, 'obrien/csharp-stuff/fnord/index.html') + + +class TestStatic(unittest.TestCase): + + def setUp(self): + + self.settings = get_settings( + STATIC_SAVE_AS='{path}', + STATIC_URL='{path}', + PAGE_SAVE_AS=os.path.join('outpages', '{slug}.html'), + PAGE_URL='outpages/{slug}.html') + self.context = self.settings.copy() + + self.static = Static(content=None, metadata={}, settings=self.settings, + source_path=os.path.join('dir', 'foo.jpg'), context=self.context) + + self.context['filenames'] = {self.static.source_path: self.static} + + def tearDown(self): + pass + + def test_attach_to_same_dir(self): + """attach_to() overrides a static file's save_as and url. + """ + page = Page(content="fake page", + metadata={'title': 'fakepage'}, settings=self.settings, + source_path=os.path.join('dir', 'fakepage.md')) + self.static.attach_to(page) + + expected_save_as = os.path.join('outpages', 'foo.jpg') + self.assertEqual(self.static.save_as, expected_save_as) + self.assertEqual(self.static.url, path_to_url(expected_save_as)) + + def test_attach_to_parent_dir(self): + """attach_to() preserves dirs inside the linking document dir. + """ + page = Page(content="fake page", metadata={'title': 'fakepage'}, + settings=self.settings, source_path='fakepage.md') + self.static.attach_to(page) + + expected_save_as = os.path.join('outpages', 'dir', 'foo.jpg') + self.assertEqual(self.static.save_as, expected_save_as) + self.assertEqual(self.static.url, path_to_url(expected_save_as)) + + def test_attach_to_other_dir(self): + """attach_to() ignores dirs outside the linking document dir. + """ + page = Page(content="fake page", + metadata={'title': 'fakepage'}, settings=self.settings, + source_path=os.path.join('dir', 'otherdir', 'fakepage.md')) + self.static.attach_to(page) + + expected_save_as = os.path.join('outpages', 'foo.jpg') + self.assertEqual(self.static.save_as, expected_save_as) + self.assertEqual(self.static.url, path_to_url(expected_save_as)) + + def test_attach_to_ignores_subsequent_calls(self): + """attach_to() does nothing when called a second time. + """ + page = Page(content="fake page", + metadata={'title': 'fakepage'}, settings=self.settings, + source_path=os.path.join('dir', 'fakepage.md')) + + self.static.attach_to(page) + + otherdir_settings = self.settings.copy() + otherdir_settings.update(dict( + PAGE_SAVE_AS=os.path.join('otherpages', '{slug}.html'), + PAGE_URL='otherpages/{slug}.html')) + otherdir_page = Page(content="other page", + metadata={'title': 'otherpage'}, settings=otherdir_settings, + source_path=os.path.join('dir', 'otherpage.md')) + + self.static.attach_to(otherdir_page) + + otherdir_save_as = os.path.join('otherpages', 'foo.jpg') + self.assertNotEqual(self.static.save_as, otherdir_save_as) + self.assertNotEqual(self.static.url, path_to_url(otherdir_save_as)) + + def test_attach_to_does_nothing_after_save_as_referenced(self): + """attach_to() does nothing if the save_as was already referenced. + (For example, by a {filename} link an a document processed earlier.) + """ + original_save_as = self.static.save_as + + page = Page(content="fake page", + metadata={'title': 'fakepage'}, settings=self.settings, + source_path=os.path.join('dir', 'fakepage.md')) + self.static.attach_to(page) + + self.assertEqual(self.static.save_as, original_save_as) + self.assertEqual(self.static.url, path_to_url(original_save_as)) + + def test_attach_to_does_nothing_after_url_referenced(self): + """attach_to() does nothing if the url was already referenced. + (For example, by a {filename} link an a document processed earlier.) + """ + original_url = self.static.url + + page = Page(content="fake page", + metadata={'title': 'fakepage'}, settings=self.settings, + source_path=os.path.join('dir', 'fakepage.md')) + self.static.attach_to(page) + + self.assertEqual(self.static.save_as, self.static.source_path) + self.assertEqual(self.static.url, original_url) + + def test_attach_to_does_not_override_an_override(self): + """attach_to() does not override paths that were overridden elsewhere. + (For example, by the user with EXTRA_PATH_METADATA) + """ + customstatic = Static(content=None, + metadata=dict(save_as='customfoo.jpg', url='customfoo.jpg'), + settings=self.settings, + source_path=os.path.join('dir', 'foo.jpg'), + context=self.settings.copy()) + + page = Page(content="fake page", + metadata={'title': 'fakepage'}, settings=self.settings, + source_path=os.path.join('dir', 'fakepage.md')) + + customstatic.attach_to(page) + + self.assertEqual(customstatic.save_as, 'customfoo.jpg') + self.assertEqual(customstatic.url, 'customfoo.jpg') + + def test_attach_link_syntax(self): + """{attach} link syntax triggers output path override & url replacement. + """ + html = 'link' + page = Page(content=html, + metadata={'title': 'fakepage'}, settings=self.settings, + source_path=os.path.join('dir', 'otherdir', 'fakepage.md'), + context=self.context) + content = page.get_content('') + + self.assertNotEqual(content, html, + "{attach} link syntax did not trigger URL replacement.") + + expected_save_as = os.path.join('outpages', 'foo.jpg') + self.assertEqual(self.static.save_as, expected_save_as) + self.assertEqual(self.static.url, path_to_url(expected_save_as)) + + +class TestURLWrapper(unittest.TestCase): + def test_comparisons(self): + # URLWrappers are sorted by name + wrapper_a = URLWrapper(name='first', settings={}) + wrapper_b = URLWrapper(name='last', settings={}) + self.assertFalse(wrapper_a > wrapper_b) + self.assertFalse(wrapper_a >= wrapper_b) + self.assertFalse(wrapper_a == wrapper_b) + self.assertTrue(wrapper_a != wrapper_b) + self.assertTrue(wrapper_a <= wrapper_b) + self.assertTrue(wrapper_a < wrapper_b) + wrapper_b.name = 'first' + self.assertFalse(wrapper_a > wrapper_b) + self.assertTrue(wrapper_a >= wrapper_b) + self.assertTrue(wrapper_a == wrapper_b) + self.assertFalse(wrapper_a != wrapper_b) + self.assertTrue(wrapper_a <= wrapper_b) + self.assertFalse(wrapper_a < wrapper_b) + wrapper_a.name = 'last' + self.assertTrue(wrapper_a > wrapper_b) + self.assertTrue(wrapper_a >= wrapper_b) + self.assertFalse(wrapper_a == wrapper_b) + self.assertTrue(wrapper_a != wrapper_b) + self.assertFalse(wrapper_a <= wrapper_b) + self.assertFalse(wrapper_a < wrapper_b) diff --git a/pelican/tests/test_generators.py b/pelican/tests/test_generators.py new file mode 100644 index 00000000..4be1b35e --- /dev/null +++ b/pelican/tests/test_generators.py @@ -0,0 +1,658 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +import os +from codecs import open +try: + from unittest.mock import MagicMock +except ImportError: + from mock import MagicMock +from operator import itemgetter +from shutil import rmtree +from tempfile import mkdtemp + +from pelican.generators import (Generator, ArticlesGenerator, PagesGenerator, + StaticGenerator, TemplatePagesGenerator) +from pelican.writers import Writer +from pelican.tests.support import unittest, get_settings +import locale + +CUR_DIR = os.path.dirname(__file__) +CONTENT_DIR = os.path.join(CUR_DIR, 'content') + + +class TestGenerator(unittest.TestCase): + def setUp(self): + self.old_locale = locale.setlocale(locale.LC_ALL) + locale.setlocale(locale.LC_ALL, str('C')) + self.settings = get_settings() + self.settings['READERS'] = {'asc': None} + self.generator = Generator(self.settings.copy(), self.settings, + CUR_DIR, self.settings['THEME'], None) + + def tearDown(self): + locale.setlocale(locale.LC_ALL, self.old_locale) + + + def test_include_path(self): + filename = os.path.join(CUR_DIR, 'content', 'article.rst') + include_path = self.generator._include_path + self.assertTrue(include_path(filename)) + self.assertTrue(include_path(filename, extensions=('rst',))) + self.assertFalse(include_path(filename, extensions=('md',))) + + def test_get_files_exclude(self): + """Test that Generator.get_files() properly excludes directories. + """ + # We use our own Generator so we can give it our own content path + generator = Generator(context=self.settings.copy(), + settings=self.settings, + path=os.path.join(CUR_DIR, 'nested_content'), + theme=self.settings['THEME'], output_path=None) + + filepaths = generator.get_files(paths=['maindir']) + found_files = {os.path.basename(f) for f in filepaths} + expected_files = {'maindir.md', 'subdir.md'} + self.assertFalse(expected_files - found_files, + "get_files() failed to find one or more files") + + filepaths = generator.get_files(paths=[''], exclude=['maindir']) + found_files = {os.path.basename(f) for f in filepaths} + self.assertNotIn('maindir.md', found_files, + "get_files() failed to exclude a top-level directory") + self.assertNotIn('subdir.md', found_files, + "get_files() failed to exclude a subdir of an excluded directory") + + filepaths = generator.get_files(paths=[''], + exclude=[os.path.join('maindir', 'subdir')]) + found_files = {os.path.basename(f) for f in filepaths} + self.assertNotIn('subdir.md', found_files, + "get_files() failed to exclude a subdirectory") + + filepaths = generator.get_files(paths=[''], exclude=['subdir']) + found_files = {os.path.basename(f) for f in filepaths} + self.assertIn('subdir.md', found_files, + "get_files() excluded a subdirectory by name, ignoring its path") + +class TestArticlesGenerator(unittest.TestCase): + + @classmethod + def setUpClass(cls): + settings = get_settings(filenames={}) + settings['DEFAULT_CATEGORY'] = 'Default' + settings['DEFAULT_DATE'] = (1970, 1, 1) + settings['READERS'] = {'asc': None} + settings['CACHE_CONTENT'] = False # cache not needed for this logic tests + + cls.generator = ArticlesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + cls.generator.generate_context() + cls.articles = cls.distill_articles(cls.generator.articles) + + def setUp(self): + self.temp_cache = mkdtemp(prefix='pelican_cache.') + + def tearDown(self): + rmtree(self.temp_cache) + + @staticmethod + def distill_articles(articles): + return [[article.title, article.status, article.category.name, + article.template] for article in articles] + + def test_generate_feeds(self): + settings = get_settings() + settings['CACHE_PATH'] = self.temp_cache + generator = ArticlesGenerator( + context=settings, settings=settings, + path=None, theme=settings['THEME'], output_path=None) + writer = MagicMock() + generator.generate_feeds(writer) + writer.write_feed.assert_called_with([], settings, + 'feeds/all.atom.xml') + + generator = ArticlesGenerator( + context=settings, settings=get_settings(FEED_ALL_ATOM=None), + path=None, theme=settings['THEME'], output_path=None) + writer = MagicMock() + generator.generate_feeds(writer) + self.assertFalse(writer.write_feed.called) + + def test_generate_context(self): + + articles_expected = [ + ['Article title', 'published', 'Default', 'article'], + ['Article with markdown and summary metadata multi', 'published', + 'Default', 'article'], + ['Article with markdown and summary metadata single', 'published', + 'Default', 'article'], + ['Article with markdown containing footnotes', 'published', + 'Default', 'article'], + ['Article with template', 'published', 'Default', 'custom'], + ['Rst with filename metadata', 'published', 'yeah', 'article'], + ['Test Markdown extensions', 'published', 'Default', 'article'], + ['Test markdown File', 'published', 'test', 'article'], + ['Test md File', 'published', 'test', 'article'], + ['Test mdown File', 'published', 'test', 'article'], + ['Test mkd File', 'published', 'test', 'article'], + ['This is a super article !', 'published', 'Yeah', 'article'], + ['This is a super article !', 'published', 'Yeah', 'article'], + ['Article with Nonconformant HTML meta tags', 'published', 'Default', 'article'], + ['This is a super article !', 'published', 'yeah', 'article'], + ['This is a super article !', 'published', 'yeah', 'article'], + ['This is a super article !', 'published', 'yeah', 'article'], + ['This is a super article !', 'published', 'Default', 'article'], + ['This is an article with category !', 'published', 'yeah', + 'article'], + ['This is an article with multiple authors!', 'published', 'Default', 'article'], + ['This is an article with multiple authors!', 'published', 'Default', 'article'], + ['This is an article without category !', 'published', 'Default', + 'article'], + ['This is an article without category !', 'published', + 'TestCategory', 'article'], + ['An Article With Code Block To Test Typogrify Ignore', + 'published', 'Default', 'article'], + ['マックOS X 10.8でパイソンとVirtualenvをインストールと設定', 'published', + '指導書', 'article'], + ] + self.assertEqual(sorted(articles_expected), sorted(self.articles)) + + def test_generate_categories(self): + + # test for name + # categories are grouped by slug; if two categories have the same slug + # but different names they will be grouped together, the first one in + # terms of process order will define the name for that category + categories = [cat.name for cat, _ in self.generator.categories] + categories_alternatives = ( + sorted(['Default', 'TestCategory', 'Yeah', 'test', '指導書']), + sorted(['Default', 'TestCategory', 'yeah', 'test', '指導書']), + ) + self.assertIn(sorted(categories), categories_alternatives) + # test for slug + categories = [cat.slug for cat, _ in self.generator.categories] + categories_expected = ['default', 'testcategory', 'yeah', 'test', + 'zhi-dao-shu'] + self.assertEqual(sorted(categories), sorted(categories_expected)) + + def test_do_not_use_folder_as_category(self): + + settings = get_settings(filenames={}) + settings['DEFAULT_CATEGORY'] = 'Default' + settings['DEFAULT_DATE'] = (1970, 1, 1) + settings['USE_FOLDER_AS_CATEGORY'] = False + settings['CACHE_PATH'] = self.temp_cache + settings['READERS'] = {'asc': None} + settings['filenames'] = {} + generator = ArticlesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.generate_context() + # test for name + # categories are grouped by slug; if two categories have the same slug + # but different names they will be grouped together, the first one in + # terms of process order will define the name for that category + categories = [cat.name for cat, _ in generator.categories] + categories_alternatives = ( + sorted(['Default', 'Yeah', 'test', '指導書']), + sorted(['Default', 'yeah', 'test', '指導書']), + ) + self.assertIn(sorted(categories), categories_alternatives) + # test for slug + categories = [cat.slug for cat, _ in generator.categories] + categories_expected = ['default', 'yeah', 'test', 'zhi-dao-shu'] + self.assertEqual(sorted(categories), sorted(categories_expected)) + + def test_direct_templates_save_as_default(self): + + settings = get_settings(filenames={}) + settings['CACHE_PATH'] = self.temp_cache + generator = ArticlesGenerator( + context=settings, settings=settings, + path=None, theme=settings['THEME'], output_path=None) + write = MagicMock() + generator.generate_direct_templates(write) + write.assert_called_with("archives.html", + generator.get_template("archives"), settings, + blog=True, paginated={}, page_name='archives') + + def test_direct_templates_save_as_modified(self): + + settings = get_settings() + settings['DIRECT_TEMPLATES'] = ['archives'] + settings['ARCHIVES_SAVE_AS'] = 'archives/index.html' + settings['CACHE_PATH'] = self.temp_cache + generator = ArticlesGenerator( + context=settings, settings=settings, + path=None, theme=settings['THEME'], output_path=None) + write = MagicMock() + generator.generate_direct_templates(write) + write.assert_called_with("archives/index.html", + generator.get_template("archives"), settings, + blog=True, paginated={}, + page_name='archives/index') + + def test_direct_templates_save_as_false(self): + + settings = get_settings() + settings['DIRECT_TEMPLATES'] = ['archives'] + settings['ARCHIVES_SAVE_AS'] = False + settings['CACHE_PATH'] = self.temp_cache + generator = ArticlesGenerator( + context=settings, settings=settings, + path=None, theme=settings['THEME'], output_path=None) + write = MagicMock() + generator.generate_direct_templates(write) + self.assertEqual(write.call_count, 0) + + def test_per_article_template(self): + """ + Custom template articles get the field but standard/unset are None + """ + custom_template = ['Article with template', 'published', 'Default', + 'custom'] + standard_template = ['This is a super article !', 'published', 'Yeah', + 'article'] + self.assertIn(custom_template, self.articles) + self.assertIn(standard_template, self.articles) + + def test_period_in_timeperiod_archive(self): + """ + Test that the context of a generated period_archive is passed + 'period' : a tuple of year, month, day according to the time period + """ + settings = get_settings(filenames={}) + + settings['YEAR_ARCHIVE_SAVE_AS'] = 'posts/{date:%Y}/index.html' + settings['CACHE_PATH'] = self.temp_cache + generator = ArticlesGenerator( + context=settings, settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.generate_context() + write = MagicMock() + generator.generate_period_archives(write) + dates = [d for d in generator.dates if d.date.year == 1970] + self.assertEqual(len(dates), 1) + #among other things it must have at least been called with this + settings["period"] = (1970,) + write.assert_called_with("posts/1970/index.html", + generator.get_template("period_archives"), + settings, + blog=True, dates=dates) + + del settings["period"] + settings['MONTH_ARCHIVE_SAVE_AS'] = 'posts/{date:%Y}/{date:%b}/index.html' + generator = ArticlesGenerator( + context=settings, settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.generate_context() + write = MagicMock() + generator.generate_period_archives(write) + dates = [d for d in generator.dates if d.date.year == 1970 + and d.date.month == 1] + self.assertEqual(len(dates), 1) + settings["period"] = (1970, "January") + #among other things it must have at least been called with this + write.assert_called_with("posts/1970/Jan/index.html", + generator.get_template("period_archives"), + settings, + blog=True, dates=dates) + + del settings["period"] + settings['DAY_ARCHIVE_SAVE_AS'] = 'posts/{date:%Y}/{date:%b}/{date:%d}/index.html' + generator = ArticlesGenerator( + context=settings, settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.generate_context() + write = MagicMock() + generator.generate_period_archives(write) + dates = [d for d in generator.dates if d.date.year == 1970 + and d.date.month == 1 + and d.date.day == 1] + self.assertEqual(len(dates), 1) + settings["period"] = (1970, "January", 1) + #among other things it must have at least been called with this + write.assert_called_with("posts/1970/Jan/01/index.html", + generator.get_template("period_archives"), + settings, + blog=True, dates=dates) + + def test_generate_authors(self): + """Check authors generation.""" + authors = [author.name for author, _ in self.generator.authors] + authors_expected = sorted(['Alexis Métaireau', 'First Author', 'Second Author']) + self.assertEqual(sorted(authors), authors_expected) + # test for slug + authors = [author.slug for author, _ in self.generator.authors] + authors_expected = ['alexis-metaireau', 'first-author', 'second-author'] + self.assertEqual(sorted(authors), sorted(authors_expected)) + + def test_article_object_caching(self): + """Test Article objects caching at the generator level""" + settings = get_settings(filenames={}) + settings['CACHE_PATH'] = self.temp_cache + settings['CONTENT_CACHING_LAYER'] = 'generator' + settings['READERS'] = {'asc': None} + + generator = ArticlesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.generate_context() + self.assertTrue(hasattr(generator, '_cache')) + + generator = ArticlesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.readers.read_file = MagicMock() + generator.generate_context() + generator.readers.read_file.assert_called_count == 0 + + def test_reader_content_caching(self): + """Test raw content caching at the reader level""" + settings = get_settings(filenames={}) + settings['CACHE_PATH'] = self.temp_cache + settings['READERS'] = {'asc': None} + + generator = ArticlesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.generate_context() + self.assertTrue(hasattr(generator.readers, '_cache')) + + generator = ArticlesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + readers = generator.readers.readers + for reader in readers.values(): + reader.read = MagicMock() + generator.generate_context() + for reader in readers.values(): + reader.read.assert_called_count == 0 + + def test_ignore_cache(self): + """Test that all the articles are read again when not loading cache + + used in --ignore-cache or autoreload mode""" + settings = get_settings(filenames={}) + settings['CACHE_PATH'] = self.temp_cache + settings['READERS'] = {'asc': None} + + generator = ArticlesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.readers.read_file = MagicMock() + generator.generate_context() + self.assertTrue(hasattr(generator, '_cache_open')) + orig_call_count = generator.readers.read_file.call_count + + settings['LOAD_CONTENT_CACHE'] = False + generator = ArticlesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.readers.read_file = MagicMock() + generator.generate_context() + generator.readers.read_file.assert_called_count == orig_call_count + + +class TestPageGenerator(unittest.TestCase): + # Note: Every time you want to test for a new field; Make sure the test + # pages in "TestPages" have all the fields Add it to distilled in + # distill_pages Then update the assertEqual in test_generate_context + # to match expected + + def setUp(self): + self.temp_cache = mkdtemp(prefix='pelican_cache.') + + def tearDown(self): + rmtree(self.temp_cache) + + def distill_pages(self, pages): + return [[page.title, page.status, page.template] for page in pages] + + def test_generate_context(self): + settings = get_settings(filenames={}) + settings['CACHE_PATH'] = self.temp_cache + settings['PAGE_PATHS'] = ['TestPages'] # relative to CUR_DIR + settings['DEFAULT_DATE'] = (1970, 1, 1) + + generator = PagesGenerator( + context=settings.copy(), settings=settings, + path=CUR_DIR, theme=settings['THEME'], output_path=None) + generator.generate_context() + pages = self.distill_pages(generator.pages) + hidden_pages = self.distill_pages(generator.hidden_pages) + + pages_expected = [ + ['This is a test page', 'published', 'page'], + ['This is a markdown test page', 'published', 'page'], + ['This is a test page with a preset template', 'published', + 'custom'], + ['A Page (Test) for sorting', 'published', 'page'], + ] + hidden_pages_expected = [ + ['This is a test hidden page', 'hidden', 'page'], + ['This is a markdown test hidden page', 'hidden', 'page'], + ['This is a test hidden page with a custom template', 'hidden', + 'custom'] + ] + + self.assertEqual(sorted(pages_expected), sorted(pages)) + self.assertEqual(sorted(hidden_pages_expected), sorted(hidden_pages)) + + def test_page_object_caching(self): + """Test Page objects caching at the generator level""" + settings = get_settings(filenames={}) + settings['CACHE_PATH'] = self.temp_cache + settings['CONTENT_CACHING_LAYER'] = 'generator' + settings['READERS'] = {'asc': None} + + generator = PagesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.generate_context() + self.assertTrue(hasattr(generator, '_cache')) + + generator = PagesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.readers.read_file = MagicMock() + generator.generate_context() + generator.readers.read_file.assert_called_count == 0 + + def test_reader_content_caching(self): + """Test raw content caching at the reader level""" + settings = get_settings(filenames={}) + settings['CACHE_PATH'] = self.temp_cache + settings['READERS'] = {'asc': None} + + generator = PagesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.generate_context() + self.assertTrue(hasattr(generator.readers, '_cache')) + + generator = PagesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + readers = generator.readers.readers + for reader in readers.values(): + reader.read = MagicMock() + generator.generate_context() + for reader in readers.values(): + reader.read.assert_called_count == 0 + + def test_ignore_cache(self): + """Test that all the pages are read again when not loading cache + + used in --ignore_cache or autoreload mode""" + settings = get_settings(filenames={}) + settings['CACHE_PATH'] = self.temp_cache + settings['READERS'] = {'asc': None} + + generator = PagesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.readers.read_file = MagicMock() + generator.generate_context() + self.assertTrue(hasattr(generator, '_cache_open')) + orig_call_count = generator.readers.read_file.call_count + + settings['LOAD_CONTENT_CACHE'] = False + generator = PagesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.readers.read_file = MagicMock() + generator.generate_context() + generator.readers.read_file.assert_called_count == orig_call_count + + def test_generate_sorted(self): + settings = get_settings(filenames={}) + settings['PAGE_PATHS'] = ['TestPages'] # relative to CUR_DIR + settings['CACHE_PATH'] = self.temp_cache + settings['DEFAULT_DATE'] = (1970, 1, 1) + + # default sort (filename) + pages_expected_sorted_by_filename = [ + ['This is a test page', 'published', 'page'], + ['This is a markdown test page', 'published', 'page'], + ['A Page (Test) for sorting', 'published', 'page'], + ['This is a test page with a preset template', 'published', + 'custom'], + ] + generator = PagesGenerator( + context=settings.copy(), settings=settings, + path=CUR_DIR, theme=settings['THEME'], output_path=None) + generator.generate_context() + pages = self.distill_pages(generator.pages) + self.assertEqual(pages_expected_sorted_by_filename, pages) + + # sort by title + pages_expected_sorted_by_title = [ + ['A Page (Test) for sorting', 'published', 'page'], + ['This is a markdown test page', 'published', 'page'], + ['This is a test page', 'published', 'page'], + ['This is a test page with a preset template', 'published', + 'custom'], + ] + settings['PAGE_ORDER_BY'] = 'title' + generator = PagesGenerator( + context=settings.copy(), settings=settings, + path=CUR_DIR, theme=settings['THEME'], output_path=None) + generator.generate_context() + pages = self.distill_pages(generator.pages) + self.assertEqual(pages_expected_sorted_by_title, pages) + + +class TestTemplatePagesGenerator(unittest.TestCase): + + TEMPLATE_CONTENT = "foo: {{ foo }}" + + def setUp(self): + self.temp_content = mkdtemp(prefix='pelicantests.') + self.temp_output = mkdtemp(prefix='pelicantests.') + self.old_locale = locale.setlocale(locale.LC_ALL) + locale.setlocale(locale.LC_ALL, str('C')) + + + def tearDown(self): + rmtree(self.temp_content) + rmtree(self.temp_output) + locale.setlocale(locale.LC_ALL, self.old_locale) + + def test_generate_output(self): + + settings = get_settings() + settings['STATIC_PATHS'] = ['static'] + settings['TEMPLATE_PAGES'] = { + 'template/source.html': 'generated/file.html' + } + + generator = TemplatePagesGenerator( + context={'foo': 'bar'}, settings=settings, + path=self.temp_content, theme='', output_path=self.temp_output) + + # create a dummy template file + template_dir = os.path.join(self.temp_content, 'template') + template_path = os.path.join(template_dir, 'source.html') + os.makedirs(template_dir) + with open(template_path, 'w') as template_file: + template_file.write(self.TEMPLATE_CONTENT) + + writer = Writer(self.temp_output, settings=settings) + generator.generate_output(writer) + + output_path = os.path.join(self.temp_output, 'generated', 'file.html') + + # output file has been generated + self.assertTrue(os.path.exists(output_path)) + + # output content is correct + with open(output_path, 'r') as output_file: + self.assertEqual(output_file.read(), 'foo: bar') + + +class TestStaticGenerator(unittest.TestCase): + + def setUp(self): + self.content_path = os.path.join(CUR_DIR, 'mixed_content') + + def test_static_excludes(self): + """Test that StaticGenerator respects STATIC_EXCLUDES. + """ + settings = get_settings(STATIC_EXCLUDES=['subdir'], + PATH=self.content_path, STATIC_PATHS=['']) + context = settings.copy() + context['filenames'] = {} + + StaticGenerator(context=context, settings=settings, + path=settings['PATH'], output_path=None, + theme=settings['THEME']).generate_context() + + staticnames = [os.path.basename(c.source_path) + for c in context['staticfiles']] + + self.assertNotIn('subdir_fake_image.jpg', staticnames, + "StaticGenerator processed a file in a STATIC_EXCLUDES directory") + self.assertIn('fake_image.jpg', staticnames, + "StaticGenerator skipped a file that it should have included") + + def test_static_exclude_sources(self): + """Test that StaticGenerator respects STATIC_EXCLUDE_SOURCES. + """ + # Test STATIC_EXCLUDE_SOURCES=True + + settings = get_settings(STATIC_EXCLUDE_SOURCES=True, + PATH=self.content_path, PAGE_PATHS=[''], STATIC_PATHS=[''], + CACHE_CONTENT=False) + context = settings.copy() + context['filenames'] = {} + + for generator_class in (PagesGenerator, StaticGenerator): + generator_class(context=context, settings=settings, + path=settings['PATH'], output_path=None, + theme=settings['THEME']).generate_context() + + staticnames = [os.path.basename(c.source_path) + for c in context['staticfiles']] + + self.assertFalse(any(name.endswith(".md") for name in staticnames), + "STATIC_EXCLUDE_SOURCES=True failed to exclude a markdown file") + + # Test STATIC_EXCLUDE_SOURCES=False + + settings.update(STATIC_EXCLUDE_SOURCES=False) + context = settings.copy() + context['filenames'] = {} + + for generator_class in (PagesGenerator, StaticGenerator): + generator_class(context=context, settings=settings, + path=settings['PATH'], output_path=None, + theme=settings['THEME']).generate_context() + + staticnames = [os.path.basename(c.source_path) + for c in context['staticfiles']] + + self.assertTrue(any(name.endswith(".md") for name in staticnames), + "STATIC_EXCLUDE_SOURCES=False failed to include a markdown file") + diff --git a/pelican/tests/test_importer.py b/pelican/tests/test_importer.py new file mode 100644 index 00000000..65193bf5 --- /dev/null +++ b/pelican/tests/test_importer.py @@ -0,0 +1,304 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function + +import os +import re + +import locale +from pelican.tools.pelican_import import wp2fields, fields2pelican, decode_wp_content, build_header, build_markdown_header, get_attachments, download_attachments +from pelican.tests.support import (unittest, temporary_folder, mute, + skipIfNoExecutable) + +from pelican.utils import slugify + +CUR_DIR = os.path.abspath(os.path.dirname(__file__)) +WORDPRESS_XML_SAMPLE = os.path.join(CUR_DIR, 'content', 'wordpressexport.xml') +WORDPRESS_ENCODED_CONTENT_SAMPLE = os.path.join(CUR_DIR, + 'content', + 'wordpress_content_encoded') +WORDPRESS_DECODED_CONTENT_SAMPLE = os.path.join(CUR_DIR, + 'content', + 'wordpress_content_decoded') + +try: + from bs4 import BeautifulSoup +except ImportError: + BeautifulSoup = False # NOQA + + +@skipIfNoExecutable(['pandoc', '--version']) +@unittest.skipUnless(BeautifulSoup, 'Needs BeautifulSoup module') +class TestWordpressXmlImporter(unittest.TestCase): + + def setUp(self): + self.old_locale = locale.setlocale(locale.LC_ALL) + locale.setlocale(locale.LC_ALL, str('C')) + self.posts = list(wp2fields(WORDPRESS_XML_SAMPLE)) + self.custposts = list(wp2fields(WORDPRESS_XML_SAMPLE, True)) + + def tearDown(self): + locale.setlocale(locale.LC_ALL, self.old_locale) + + def test_ignore_empty_posts(self): + self.assertTrue(self.posts) + for title, content, fname, date, author, categ, tags, kind, format in self.posts: + self.assertTrue(title.strip()) + + def test_recognise_page_kind(self): + """ Check that we recognise pages in wordpress, as opposed to posts """ + self.assertTrue(self.posts) + # Collect (title, filename, kind) of non-empty posts recognised as page + pages_data = [] + for title, content, fname, date, author, categ, tags, kind, format in self.posts: + if kind == 'page': + pages_data.append((title, fname)) + self.assertEqual(2, len(pages_data)) + self.assertEqual(('Page', 'contact'), pages_data[0]) + self.assertEqual(('Empty Page', 'empty'), pages_data[1]) + + def test_dirpage_directive_for_page_kind(self): + silent_f2p = mute(True)(fields2pelican) + test_post = filter(lambda p: p[0].startswith("Empty Page"), self.posts) + with temporary_folder() as temp: + fname = list(silent_f2p(test_post, 'markdown', temp, dirpage=True))[0] + self.assertTrue(fname.endswith('pages%sempty.md' % os.path.sep)) + + def test_dircat(self): + silent_f2p = mute(True)(fields2pelican) + test_posts = [] + for post in self.posts: + # check post kind + if len(post[5]) > 0: # Has a category + test_posts.append(post) + with temporary_folder() as temp: + fnames = list(silent_f2p(test_posts, 'markdown', temp, dircat=True)) + index = 0 + for post in test_posts: + name = post[2] + category = slugify(post[5][0]) + name += '.md' + filename = os.path.join(category, name) + out_name = fnames[index] + self.assertTrue(out_name.endswith(filename)) + index += 1 + + def test_unless_custom_post_all_items_should_be_pages_or_posts(self): + self.assertTrue(self.posts) + pages_data = [] + for title, content, fname, date, author, categ, tags, kind, format in self.posts: + if kind == 'page' or kind == 'article': + pass + else: + pages_data.append((title, fname)) + self.assertEqual(0, len(pages_data)) + + def test_recognise_custom_post_type(self): + self.assertTrue(self.custposts) + cust_data = [] + for title, content, fname, date, author, categ, tags, kind, format in self.custposts: + if kind == 'article' or kind == 'page': + pass + else: + cust_data.append((title, kind)) + self.assertEqual(3, len(cust_data)) + self.assertEqual(('A custom post in category 4', 'custom1'), cust_data[0]) + self.assertEqual(('A custom post in category 5', 'custom1'), cust_data[1]) + self.assertEqual(('A 2nd custom post type also in category 5', 'custom2'), cust_data[2]) + + def test_custom_posts_put_in_own_dir(self): + silent_f2p = mute(True)(fields2pelican) + test_posts = [] + for post in self.custposts: + # check post kind + if post[7] == 'article' or post[7] == 'page': + pass + else: + test_posts.append(post) + with temporary_folder() as temp: + fnames = list(silent_f2p(test_posts, 'markdown', temp, wp_custpost = True)) + index = 0 + for post in test_posts: + name = post[2] + kind = post[7] + name += '.md' + filename = os.path.join(kind, name) + out_name = fnames[index] + self.assertTrue(out_name.endswith(filename)) + index += 1 + + def test_custom_posts_put_in_own_dir_and_catagory_sub_dir(self): + silent_f2p = mute(True)(fields2pelican) + test_posts = [] + for post in self.custposts: + # check post kind + if post[7] == 'article' or post[7] == 'page': + pass + else: + test_posts.append(post) + with temporary_folder() as temp: + fnames = list(silent_f2p(test_posts, 'markdown', temp, + wp_custpost=True, dircat=True)) + index = 0 + for post in test_posts: + name = post[2] + kind = post[7] + category = slugify(post[5][0]) + name += '.md' + filename = os.path.join(kind, category, name) + out_name = fnames[index] + self.assertTrue(out_name.endswith(filename)) + index += 1 + + def test_wp_custpost_true_dirpage_false(self): + #pages should only be put in their own directory when dirpage = True + silent_f2p = mute(True)(fields2pelican) + test_posts = [] + for post in self.custposts: + # check post kind + if post[7] == 'page': + test_posts.append(post) + with temporary_folder() as temp: + fnames = list(silent_f2p(test_posts, 'markdown', temp, + wp_custpost=True, dirpage=False)) + index = 0 + for post in test_posts: + name = post[2] + name += '.md' + filename = os.path.join('pages', name) + out_name = fnames[index] + self.assertFalse(out_name.endswith(filename)) + + + def test_can_toggle_raw_html_code_parsing(self): + def r(f): + with open(f) as infile: + return infile.read() + silent_f2p = mute(True)(fields2pelican) + + with temporary_folder() as temp: + + rst_files = (r(f) for f in silent_f2p(self.posts, 'markdown', temp)) + self.assertTrue(any(' entities in the" + " title. You can't miss them.") + self.assertNotIn('&', title) + + def test_decode_wp_content_returns_empty(self): + """ Check that given an empty string we return an empty string.""" + self.assertEqual(decode_wp_content(""), "") + + def test_decode_wp_content(self): + """ Check that we can decode a wordpress content string.""" + with open(WORDPRESS_ENCODED_CONTENT_SAMPLE, 'r') as encoded_file: + encoded_content = encoded_file.read() + with open(WORDPRESS_DECODED_CONTENT_SAMPLE, 'r') as decoded_file: + decoded_content = decoded_file.read() + self.assertEqual(decode_wp_content(encoded_content, br=False), decoded_content) + + def test_preserve_verbatim_formatting(self): + def r(f): + with open(f) as infile: + return infile.read() + silent_f2p = mute(True)(fields2pelican) + test_post = filter(lambda p: p[0].startswith("Code in List"), self.posts) + with temporary_folder() as temp: + md = [r(f) for f in silent_f2p(test_post, 'markdown', temp)][0] + self.assertTrue(re.search(r'\s+a = \[1, 2, 3\]', md)) + self.assertTrue(re.search(r'\s+b = \[4, 5, 6\]', md)) + + for_line = re.search(r'\s+for i in zip\(a, b\):', md).group(0) + print_line = re.search(r'\s+print i', md).group(0) + self.assertTrue(for_line.rindex('for') < print_line.rindex('print')) + + def test_code_in_list(self): + def r(f): + with open(f) as infile: + return infile.read() + silent_f2p = mute(True)(fields2pelican) + test_post = filter(lambda p: p[0].startswith("Code in List"), self.posts) + with temporary_folder() as temp: + md = [r(f) for f in silent_f2p(test_post, 'markdown', temp)][0] + sample_line = re.search(r'- This is a code sample', md).group(0) + code_line = re.search(r'\s+a = \[1, 2, 3\]', md).group(0) + self.assertTrue(sample_line.rindex('This') < code_line.rindex('a')) + + +class TestBuildHeader(unittest.TestCase): + def test_build_header(self): + header = build_header('test', None, None, None, None, None) + self.assertEqual(header, 'test\n####\n\n') + + def test_build_header_with_east_asian_characters(self): + header = build_header('これは広い幅の文字だけで構成されたタイトルです', + None, None, None, None, None) + + self.assertEqual(header, + 'これは広い幅の文字だけで構成されたタイトルです\n' + + '##############################################\n\n') + + def test_galleries_added_to_header(self): + header = build_header('test', None, None, None, None, + None, ['output/test1', 'output/test2']) + self.assertEqual(header, 'test\n####\n' + ':attachments: output/test1, ' + + 'output/test2\n\n') + + def test_galleries_added_to_markdown_header(self): + header = build_markdown_header('test', None, None, None, None, None, + ['output/test1', 'output/test2']) + self.assertEqual(header, 'Title: test\n' + 'Attachments: output/test1, ' + + 'output/test2\n\n') + +@unittest.skipUnless(BeautifulSoup, 'Needs BeautifulSoup module') +class TestWordpressXMLAttachements(unittest.TestCase): + def setUp(self): + self.old_locale = locale.setlocale(locale.LC_ALL) + locale.setlocale(locale.LC_ALL, str('C')) + self.attachments = get_attachments(WORDPRESS_XML_SAMPLE) + + def tearDown(self): + locale.setlocale(locale.LC_ALL, self.old_locale) + + def test_recognise_attachments(self): + self.assertTrue(self.attachments) + self.assertTrue(len(self.attachments.keys()) == 3) + + def test_attachments_associated_with_correct_post(self): + self.assertTrue(self.attachments) + for post in self.attachments.keys(): + if post is None: + self.assertTrue(self.attachments[post][0] == 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Pelican_lakes_entrance02.jpg/240px-Pelican_lakes_entrance02.jpg') + elif post == 'with-excerpt': + self.assertTrue(self.attachments[post][0] == 'http://thisurlisinvalid.notarealdomain/not_an_image.jpg') + self.assertTrue(self.attachments[post][1] == 'http://en.wikipedia.org/wiki/File:Pelikan_Walvis_Bay.jpg') + elif post == 'with-tags': + self.assertTrue(self.attachments[post][0] == 'http://thisurlisinvalid.notarealdomain') + else: + self.fail('all attachments should match to a filename or None, {}'.format(post)) + + def test_download_attachments(self): + real_file = os.path.join(CUR_DIR, 'content/article.rst') + good_url = 'file://' + real_file + bad_url = 'http://localhost:1/not_a_file.txt' + silent_da = mute()(download_attachments) + with temporary_folder() as temp: + #locations = download_attachments(temp, [good_url, bad_url]) + locations = list(silent_da(temp, [good_url, bad_url])) + self.assertTrue(len(locations) == 1) + directory = locations[0] + self.assertTrue(directory.endswith('content/article.rst')) diff --git a/pelican/tests/test_paginator.py b/pelican/tests/test_paginator.py new file mode 100644 index 00000000..108dc791 --- /dev/null +++ b/pelican/tests/test_paginator.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, absolute_import +import six +import locale + +from pelican.tests.support import unittest, get_settings + +from pelican.paginator import Paginator +from pelican.contents import Article +from pelican.settings import DEFAULT_CONFIG +from jinja2.utils import generate_lorem_ipsum + +# generate one paragraph, enclosed with

    +TEST_CONTENT = str(generate_lorem_ipsum(n=1)) +TEST_SUMMARY = generate_lorem_ipsum(n=1, html=False) + +class TestPage(unittest.TestCase): + def setUp(self): + super(TestPage, self).setUp() + self.old_locale = locale.setlocale(locale.LC_ALL) + locale.setlocale(locale.LC_ALL, str('C')) + self.page_kwargs = { + 'content': TEST_CONTENT, + 'context': { + 'localsiteurl': '', + }, + 'metadata': { + 'summary': TEST_SUMMARY, + 'title': 'foo bar', + 'author': 'Blogger', + }, + 'source_path': '/path/to/file/foo.ext' + } + + def tearDown(self): + locale.setlocale(locale.LC_ALL, self.old_locale) + + def test_save_as_preservation(self): + settings = get_settings() + # fix up pagination rules + from pelican.paginator import PaginationRule + pagination_rules = [ + PaginationRule(*r) for r in settings.get( + 'PAGINATION_PATTERNS', + DEFAULT_CONFIG['PAGINATION_PATTERNS'], + ) + ] + settings['PAGINATION_PATTERNS'] = sorted( + pagination_rules, + key=lambda r: r[0], + ) + + object_list = [Article(**self.page_kwargs), Article(**self.page_kwargs)] + paginator = Paginator('foobar.foo', object_list, settings) + page = paginator.page(1) + self.assertEqual(page.save_as, 'foobar.foo') diff --git a/pelican/tests/test_pelican.py b/pelican/tests/test_pelican.py new file mode 100644 index 00000000..190d5e06 --- /dev/null +++ b/pelican/tests/test_pelican.py @@ -0,0 +1,201 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function + +import collections +import os +import sys +from tempfile import mkdtemp +from shutil import rmtree +import locale +import logging +import subprocess + +from pelican import Pelican +from pelican.generators import StaticGenerator +from pelican.settings import read_settings +from pelican.tests.support import LoggedTestCase, mute, locale_available, unittest + +CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) +SAMPLES_PATH = os.path.abspath(os.path.join( + CURRENT_DIR, os.pardir, os.pardir, 'samples')) +OUTPUT_PATH = os.path.abspath(os.path.join(CURRENT_DIR, 'output')) + +INPUT_PATH = os.path.join(SAMPLES_PATH, "content") +SAMPLE_CONFIG = os.path.join(SAMPLES_PATH, "pelican.conf.py") +SAMPLE_FR_CONFIG = os.path.join(SAMPLES_PATH, "pelican.conf_FR.py") + + +def recursiveDiff(dcmp): + diff = { + 'diff_files': [os.path.join(dcmp.right, f) + for f in dcmp.diff_files], + 'left_only': [os.path.join(dcmp.right, f) + for f in dcmp.left_only], + 'right_only': [os.path.join(dcmp.right, f) + for f in dcmp.right_only], + } + for sub_dcmp in dcmp.subdirs.values(): + for k, v in recursiveDiff(sub_dcmp).items(): + diff[k] += v + return diff + + +class TestPelican(LoggedTestCase): + # general functional testing for pelican. Basically, this test case tries + # to run pelican in different situations and see how it behaves + + def setUp(self): + super(TestPelican, self).setUp() + self.temp_path = mkdtemp(prefix='pelicantests.') + self.temp_cache = mkdtemp(prefix='pelican_cache.') + self.maxDiff = None + self.old_locale = locale.setlocale(locale.LC_ALL) + locale.setlocale(locale.LC_ALL, str('C')) + + def tearDown(self): + rmtree(self.temp_path) + rmtree(self.temp_cache) + locale.setlocale(locale.LC_ALL, self.old_locale) + super(TestPelican, self).tearDown() + + def assertFilesEqual(self, diff): + msg = ("some generated files differ from the expected functional " + "tests output.\n" + "This is probably because the HTML generated files " + "changed. If these changes are normal, please refer " + "to docs/contribute.rst to update the expected " + "output of the functional tests.") + + self.assertEqual(diff['left_only'], [], msg=msg) + self.assertEqual(diff['right_only'], [], msg=msg) + self.assertEqual(diff['diff_files'], [], msg=msg) + + def assertDirsEqual(self, left_path, right_path): + out, err = subprocess.Popen( + ['git', 'diff', '--no-ext-diff', '--exit-code', '-w', left_path, right_path], env={'PAGER': ''}, + stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() + assert not out, out + assert not err, err + + def test_order_of_generators(self): + # StaticGenerator must run last, so it can identify files that + # were skipped by the other generators, and so static files can + # have their output paths overridden by the {attach} link syntax. + + pelican = Pelican(settings=read_settings(path=None)) + generator_classes = pelican.get_generator_classes() + + self.assertTrue(generator_classes[-1] is StaticGenerator, + "StaticGenerator must be the last generator, but it isn't!") + self.assertIsInstance(generator_classes, collections.Sequence, + "get_generator_classes() must return a Sequence to preserve order") + + def test_basic_generation_works(self): + # when running pelican without settings, it should pick up the default + # ones and generate correct output without raising any exception + settings = read_settings(path=None, override={ + 'PATH': INPUT_PATH, + 'OUTPUT_PATH': self.temp_path, + 'CACHE_PATH': self.temp_cache, + 'LOCALE': locale.normalize('en_US'), + }) + pelican = Pelican(settings=settings) + mute(True)(pelican.run)() + self.assertDirsEqual(self.temp_path, os.path.join(OUTPUT_PATH, 'basic')) + self.assertLogCountEqual( + count=3, + msg="Unable to find.*skipping url replacement", + level=logging.WARNING) + + def test_custom_generation_works(self): + # the same thing with a specified set of settings should work + settings = read_settings(path=SAMPLE_CONFIG, override={ + 'PATH': INPUT_PATH, + 'OUTPUT_PATH': self.temp_path, + 'CACHE_PATH': self.temp_cache, + 'LOCALE': locale.normalize('en_US'), + }) + pelican = Pelican(settings=settings) + mute(True)(pelican.run)() + self.assertDirsEqual(self.temp_path, os.path.join(OUTPUT_PATH, 'custom')) + + @unittest.skipUnless(locale_available('fr_FR.UTF-8') or + locale_available('French'), 'French locale needed') + def test_custom_locale_generation_works(self): + '''Test that generation with fr_FR.UTF-8 locale works''' + old_locale = locale.setlocale(locale.LC_TIME) + + if sys.platform == 'win32': + our_locale = str('French') + else: + our_locale = str('fr_FR.UTF-8') + + settings = read_settings(path=SAMPLE_FR_CONFIG, override={ + 'PATH': INPUT_PATH, + 'OUTPUT_PATH': self.temp_path, + 'CACHE_PATH': self.temp_cache, + 'LOCALE': our_locale, + }) + pelican = Pelican(settings=settings) + mute(True)(pelican.run)() + self.assertDirsEqual(self.temp_path, os.path.join(OUTPUT_PATH, 'custom_locale')) + + def test_theme_static_paths_copy(self): + # the same thing with a specified set of settings should work + settings = read_settings(path=SAMPLE_CONFIG, override={ + 'PATH': INPUT_PATH, + 'OUTPUT_PATH': self.temp_path, + 'CACHE_PATH': self.temp_cache, + 'THEME_STATIC_PATHS': [os.path.join(SAMPLES_PATH, 'very'), + os.path.join(SAMPLES_PATH, 'kinda'), + os.path.join(SAMPLES_PATH, 'theme_standard')] + }) + pelican = Pelican(settings=settings) + mute(True)(pelican.run)() + theme_output = os.path.join(self.temp_path, 'theme') + extra_path = os.path.join(theme_output, 'exciting', 'new', 'files') + + for file in ['a_stylesheet', 'a_template']: + self.assertTrue(os.path.exists(os.path.join(theme_output, file))) + + for file in ['wow!', 'boom!', 'bap!', 'zap!']: + self.assertTrue(os.path.exists(os.path.join(extra_path, file))) + + def test_theme_static_paths_copy_single_file(self): + # the same thing with a specified set of settings should work + settings = read_settings(path=SAMPLE_CONFIG, override={ + 'PATH': INPUT_PATH, + 'OUTPUT_PATH': self.temp_path, + 'CACHE_PATH': self.temp_cache, + 'THEME_STATIC_PATHS': [os.path.join(SAMPLES_PATH, 'theme_standard')] + }) + + pelican = Pelican(settings=settings) + mute(True)(pelican.run)() + theme_output = os.path.join(self.temp_path, 'theme') + + for file in ['a_stylesheet', 'a_template']: + self.assertTrue(os.path.exists(os.path.join(theme_output, file))) + + def test_write_only_selected(self): + """Test that only the selected files are written""" + settings = read_settings(path=None, override={ + 'PATH': INPUT_PATH, + 'OUTPUT_PATH': self.temp_path, + 'CACHE_PATH': self.temp_cache, + 'WRITE_SELECTED': [ + os.path.join(self.temp_path, 'oh-yeah.html'), + os.path.join(self.temp_path, 'categories.html'), + ], + 'LOCALE': locale.normalize('en_US'), + }) + pelican = Pelican(settings=settings) + logger = logging.getLogger() + orig_level = logger.getEffectiveLevel() + logger.setLevel(logging.INFO) + mute(True)(pelican.run)() + logger.setLevel(orig_level) + self.assertLogCountEqual( + count=2, + msg="Writing .*", + level=logging.INFO) diff --git a/pelican/tests/test_readers.py b/pelican/tests/test_readers.py new file mode 100644 index 00000000..ffff3478 --- /dev/null +++ b/pelican/tests/test_readers.py @@ -0,0 +1,464 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function + +import os + +from pelican import readers +from pelican.utils import SafeDatetime +from pelican.tests.support import unittest, get_settings + +CUR_DIR = os.path.dirname(__file__) +CONTENT_PATH = os.path.join(CUR_DIR, 'content') + + +def _path(*args): + return os.path.join(CONTENT_PATH, *args) + + +class ReaderTest(unittest.TestCase): + + def read_file(self, path, **kwargs): + # Isolate from future API changes to readers.read_file + r = readers.Readers(settings=get_settings(**kwargs)) + return r.read_file(base_path=CONTENT_PATH, path=path) + + +class DefaultReaderTest(ReaderTest): + + def test_readfile_unknown_extension(self): + with self.assertRaises(TypeError): + self.read_file(path='article_with_metadata.unknownextension') + + +class RstReaderTest(ReaderTest): + + def test_article_with_metadata(self): + page = self.read_file(path='article_with_metadata.rst') + expected = { + 'category': 'yeah', + 'author': 'Alexis Métaireau', + 'title': 'This is a super article !', + 'summary': '

    Multi-line metadata should be' + ' supported\nas well as inline' + ' markup and stuff to "typogrify' + '"...

    \n', + 'date': SafeDatetime(2010, 12, 2, 10, 14), + 'modified': SafeDatetime(2010, 12, 2, 10, 20), + 'tags': ['foo', 'bar', 'foobar'], + 'custom_field': 'http://notmyidea.org', + } + + for key, value in expected.items(): + self.assertEqual(value, page.metadata[key], key) + + def test_article_with_filename_metadata(self): + page = self.read_file( + path='2012-11-29_rst_w_filename_meta#foo-bar.rst', + FILENAME_METADATA=None) + expected = { + 'category': 'yeah', + 'author': 'Alexis Métaireau', + 'title': 'Rst with filename metadata', + 'reader': 'rst', + } + for key, value in page.metadata.items(): + self.assertEqual(value, expected[key], key) + + page = self.read_file( + path='2012-11-29_rst_w_filename_meta#foo-bar.rst', + FILENAME_METADATA='(?P\d{4}-\d{2}-\d{2}).*') + expected = { + 'category': 'yeah', + 'author': 'Alexis Métaireau', + 'title': 'Rst with filename metadata', + 'date': SafeDatetime(2012, 11, 29), + 'reader': 'rst', + } + for key, value in page.metadata.items(): + self.assertEqual(value, expected[key], key) + + page = self.read_file( + path='2012-11-29_rst_w_filename_meta#foo-bar.rst', + FILENAME_METADATA=( + '(?P\d{4}-\d{2}-\d{2})_' + '_(?P.*)' + '#(?P.*)-(?P.*)')) + expected = { + 'category': 'yeah', + 'author': 'Alexis Métaireau', + 'title': 'Rst with filename metadata', + 'date': SafeDatetime(2012, 11, 29), + 'slug': 'article_with_filename_metadata', + 'mymeta': 'foo', + 'reader': 'rst', + } + for key, value in page.metadata.items(): + self.assertEqual(value, expected[key], key) + + def test_article_metadata_key_lowercase(self): + # Keys of metadata should be lowercase. + reader = readers.RstReader(settings=get_settings()) + content, metadata = reader.read( + _path('article_with_uppercase_metadata.rst')) + + self.assertIn('category', metadata, 'Key should be lowercase.') + self.assertEqual('Yeah', metadata.get('category'), + 'Value keeps case.') + + def test_typogrify(self): + # if nothing is specified in the settings, the content should be + # unmodified + page = self.read_file(path='article.rst') + expected = ('

    THIS is some content. With some stuff to ' + '"typogrify"...

    \n

    Now with added ' + 'support for ' + 'TLA.

    \n') + + self.assertEqual(page.content, expected) + + try: + # otherwise, typogrify should be applied + page = self.read_file(path='article.rst', TYPOGRIFY=True) + expected = ( + '

    THIS is some content. ' + 'With some stuff to "typogrify"…

    \n' + '

    Now with added support for TLA.

    \n') + + self.assertEqual(page.content, expected) + except ImportError: + return unittest.skip('need the typogrify distribution') + + def test_typogrify_summary(self): + # if nothing is specified in the settings, the summary should be + # unmodified + page = self.read_file(path='article_with_metadata.rst') + expected = ('

    Multi-line metadata should be' + ' supported\nas well as inline' + ' markup and stuff to "typogrify' + '"...

    \n') + + self.assertEqual(page.metadata['summary'], expected) + + try: + # otherwise, typogrify should be applied + page = self.read_file(path='article_with_metadata.rst', + TYPOGRIFY=True) + expected = ('

    Multi-line metadata should be' + ' supported\nas well as inline' + ' markup and stuff to "typogrify' + '"…

    \n') + + self.assertEqual(page.metadata['summary'], expected) + except ImportError: + return unittest.skip('need the typogrify distribution') + + def test_typogrify_ignore_tags(self): + try: + # typogrify should be able to ignore user specified tags, + # but tries to be clever with widont extension + page = self.read_file(path='article.rst', TYPOGRIFY=True, + TYPOGRIFY_IGNORE_TAGS = ['p']) + expected = ('

    THIS is some content. With some stuff to ' + '"typogrify"...

    \n

    Now with added ' + 'support for ' + 'TLA.

    \n') + + self.assertEqual(page.content, expected) + + # typogrify should ignore code blocks by default because + # code blocks are composed inside the pre tag + page = self.read_file(path='article_with_code_block.rst', + TYPOGRIFY=True) + + expected = ('

    An article with some code

    \n' + '
    x'
    +                        ' &'
    +                        ' y\n
    \n' + '

    A block quote:

    \n
    \nx ' + '& y
    \n' + '

    Normal:\nx & y

    \n') + + self.assertEqual(page.content, expected) + + # instruct typogrify to also ignore blockquotes + page = self.read_file(path='article_with_code_block.rst', + TYPOGRIFY=True, TYPOGRIFY_IGNORE_TAGS = ['blockquote']) + + expected = ('

    An article with some code

    \n' + '
    x'
    +                        ' &'
    +                        ' y\n
    \n' + '

    A block quote:

    \n
    \nx ' + '& y
    \n' + '

    Normal:\nx & y

    \n') + + self.assertEqual(page.content, expected) + except ImportError: + return unittest.skip('need the typogrify distribution') + except TypeError: + return unittest.skip('need typogrify version 2.0.4 or later') + + def test_article_with_multiple_authors(self): + page = self.read_file(path='article_with_multiple_authors.rst') + expected = { + 'authors': ['First Author', 'Second Author'] + } + + for key, value in expected.items(): + self.assertEqual(value, page.metadata[key], key) + + +class MdReaderTest(ReaderTest): + + @unittest.skipUnless(readers.Markdown, "markdown isn't installed") + def test_article_with_metadata(self): + reader = readers.MarkdownReader(settings=get_settings()) + content, metadata = reader.read( + _path('article_with_md_extension.md')) + expected = { + 'category': 'test', + 'title': 'Test md File', + 'summary': '

    I have a lot to test

    ', + 'date': SafeDatetime(2010, 12, 2, 10, 14), + 'modified': SafeDatetime(2010, 12, 2, 10, 20), + 'tags': ['foo', 'bar', 'foobar'], + } + for key, value in metadata.items(): + self.assertEqual(value, expected[key], key) + + content, metadata = reader.read( + _path('article_with_markdown_and_nonascii_summary.md')) + expected = { + 'title': 'マックOS X 10.8でパイソンとVirtualenvをインストールと設定', + 'summary': '

    パイソンとVirtualenvをまっくでインストールする方法について明確に説明します。

    ', + 'category': '指導書', + 'date': SafeDatetime(2012, 12, 20), + 'modified': SafeDatetime(2012, 12, 22), + 'tags': ['パイソン', 'マック'], + 'slug': 'python-virtualenv-on-mac-osx-mountain-lion-10.8', + } + for key, value in metadata.items(): + self.assertEqual(value, expected[key], key) + + @unittest.skipUnless(readers.Markdown, "markdown isn't installed") + def test_article_with_footnote(self): + reader = readers.MarkdownReader(settings=get_settings()) + content, metadata = reader.read( + _path('article_with_markdown_and_footnote.md')) + expected_content = ( + '

    This is some content' + '1' + ' with some footnotes' + '2

    \n' + + '
    \n' + '
    \n
      \n
    1. \n' + '

      Numbered footnote ' + '

      \n' + '
    2. \n
    3. \n' + '

      Named footnote ' + '

      \n' + '
    4. \n
    \n
    ') + expected_metadata = { + 'title': 'Article with markdown containing footnotes', + 'summary': ( + '

    Summary with inline markup ' + 'should be supported.

    '), + 'date': SafeDatetime(2012, 10, 31), + 'modified': SafeDatetime(2012, 11, 1), + 'slug': 'article-with-markdown-containing-footnotes', + 'multiline': [ + 'Line Metadata should be handle properly.', + 'See syntax of Meta-Data extension of Python Markdown package:', + 'If a line is indented by 4 or more spaces,', + 'that line is assumed to be an additional line of the value', + 'for the previous keyword.', + 'A keyword may have as many lines as desired.', + ] + } + self.assertEqual(content, expected_content) + for key, value in metadata.items(): + self.assertEqual(value, expected_metadata[key], key) + + @unittest.skipUnless(readers.Markdown, "markdown isn't installed") + def test_article_with_file_extensions(self): + reader = readers.MarkdownReader(settings=get_settings()) + # test to ensure the md file extension is being processed by the + # correct reader + content, metadata = reader.read( + _path('article_with_md_extension.md')) + expected = ( + "

    Test Markdown File Header

    \n" + "

    Used for pelican test

    \n" + "

    The quick brown fox jumped over the lazy dog's back.

    ") + self.assertEqual(content, expected) + # test to ensure the mkd file extension is being processed by the + # correct reader + content, metadata = reader.read( + _path('article_with_mkd_extension.mkd')) + expected = ("

    Test Markdown File Header

    \n

    Used for pelican" + " test

    \n

    This is another markdown test file. Uses" + " the mkd extension.

    ") + self.assertEqual(content, expected) + # test to ensure the markdown file extension is being processed by the + # correct reader + content, metadata = reader.read( + _path('article_with_markdown_extension.markdown')) + expected = ("

    Test Markdown File Header

    \n

    Used for pelican" + " test

    \n

    This is another markdown test file. Uses" + " the markdown extension.

    ") + self.assertEqual(content, expected) + # test to ensure the mdown file extension is being processed by the + # correct reader + content, metadata = reader.read( + _path('article_with_mdown_extension.mdown')) + expected = ("

    Test Markdown File Header

    \n

    Used for pelican" + " test

    \n

    This is another markdown test file. Uses" + " the mdown extension.

    ") + self.assertEqual(content, expected) + + @unittest.skipUnless(readers.Markdown, "markdown isn't installed") + def test_article_with_markdown_markup_extension(self): + # test to ensure the markdown markup extension is being processed as + # expected + page = self.read_file( + path='article_with_markdown_markup_extensions.md', + MD_EXTENSIONS=['toc', 'codehilite', 'extra']) + expected = ('
    \n' + '\n' + '
    \n' + '

    Level1

    \n' + '

    Level2

    ') + + self.assertEqual(page.content, expected) + + @unittest.skipUnless(readers.Markdown, "markdown isn't installed") + def test_article_with_filename_metadata(self): + page = self.read_file( + path='2012-11-30_md_w_filename_meta#foo-bar.md', + FILENAME_METADATA=None) + expected = { + 'category': 'yeah', + 'author': 'Alexis Métaireau', + } + for key, value in expected.items(): + self.assertEqual(value, page.metadata[key], key) + + page = self.read_file( + path='2012-11-30_md_w_filename_meta#foo-bar.md', + FILENAME_METADATA='(?P\d{4}-\d{2}-\d{2}).*') + expected = { + 'category': 'yeah', + 'author': 'Alexis Métaireau', + 'date': SafeDatetime(2012, 11, 30), + } + for key, value in expected.items(): + self.assertEqual(value, page.metadata[key], key) + + page = self.read_file( + path='2012-11-30_md_w_filename_meta#foo-bar.md', + FILENAME_METADATA=( + '(?P\d{4}-\d{2}-\d{2})' + '_(?P.*)' + '#(?P.*)-(?P.*)')) + expected = { + 'category': 'yeah', + 'author': 'Alexis Métaireau', + 'date': SafeDatetime(2012, 11, 30), + 'slug': 'md_w_filename_meta', + 'mymeta': 'foo', + } + for key, value in expected.items(): + self.assertEqual(value, page.metadata[key], key) + + +class HTMLReaderTest(ReaderTest): + def test_article_with_comments(self): + page = self.read_file(path='article_with_comments.html') + + self.assertEqual(''' + Body content + + ''', page.content) + + def test_article_with_keywords(self): + page = self.read_file(path='article_with_keywords.html') + expected = { + 'tags': ['foo', 'bar', 'foobar'], + } + + for key, value in expected.items(): + self.assertEqual(value, page.metadata[key], key) + + def test_article_with_metadata(self): + page = self.read_file(path='article_with_metadata.html') + expected = { + 'category': 'yeah', + 'author': 'Alexis Métaireau', + 'title': 'This is a super article !', + 'summary': 'Summary and stuff', + 'date': SafeDatetime(2010, 12, 2, 10, 14), + 'tags': ['foo', 'bar', 'foobar'], + 'custom_field': 'http://notmyidea.org', + } + + for key, value in expected.items(): + self.assertEqual(value, page.metadata[key], key) + + def test_article_with_multiple_authors(self): + page = self.read_file(path='article_with_multiple_authors.html') + expected = { + 'authors': ['First Author', 'Second Author'] + } + + for key, value in expected.items(): + self.assertEqual(value, page.metadata[key], key) + + def test_article_with_metadata_and_contents_attrib(self): + page = self.read_file(path='article_with_metadata_and_contents.html') + expected = { + 'category': 'yeah', + 'author': 'Alexis Métaireau', + 'title': 'This is a super article !', + 'summary': 'Summary and stuff', + 'date': SafeDatetime(2010, 12, 2, 10, 14), + 'tags': ['foo', 'bar', 'foobar'], + 'custom_field': 'http://notmyidea.org', + } + for key, value in expected.items(): + self.assertEqual(value, page.metadata[key], key) + + def test_article_with_null_attributes(self): + page = self.read_file(path='article_with_null_attributes.html') + + self.assertEqual(''' + Ensure that empty attributes are copied properly. + + ''', page.content) + + def test_article_metadata_key_lowercase(self): + # Keys of metadata should be lowercase. + page = self.read_file(path='article_with_uppercase_metadata.html') + self.assertIn('category', page.metadata, 'Key should be lowercase.') + self.assertEqual('Yeah', page.metadata.get('category'), + 'Value keeps cases.') + + def test_article_with_nonconformant_meta_tags(self): + page = self.read_file(path='article_with_nonconformant_meta_tags.html') + expected = { + 'summary': 'Summary and stuff', + 'title': 'Article with Nonconformant HTML meta tags', + } + + for key, value in expected.items(): + self.assertEqual(value, page.metadata[key], key) diff --git a/pelican/tests/test_settings.py b/pelican/tests/test_settings.py new file mode 100644 index 00000000..260eff05 --- /dev/null +++ b/pelican/tests/test_settings.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function +import copy +import os +import locale +from os.path import dirname, abspath, join + +from pelican.settings import (read_settings, configure_settings, + DEFAULT_CONFIG, DEFAULT_THEME) +from pelican.tests.support import unittest + + +class TestSettingsConfiguration(unittest.TestCase): + """Provided a file, it should read it, replace the default values, + append new values to the settings (if any), and apply basic settings + optimizations. + """ + def setUp(self): + self.old_locale = locale.setlocale(locale.LC_ALL) + locale.setlocale(locale.LC_ALL, str('C')) + self.PATH = abspath(dirname(__file__)) + default_conf = join(self.PATH, 'default_conf.py') + self.settings = read_settings(default_conf) + + def tearDown(self): + locale.setlocale(locale.LC_ALL, self.old_locale) + + def test_overwrite_existing_settings(self): + self.assertEqual(self.settings.get('SITENAME'), "Alexis' log") + self.assertEqual(self.settings.get('SITEURL'), + 'http://blog.notmyidea.org') + + def test_keep_default_settings(self): + # Keep default settings if not defined. + self.assertEqual(self.settings.get('DEFAULT_CATEGORY'), + DEFAULT_CONFIG['DEFAULT_CATEGORY']) + + def test_dont_copy_small_keys(self): + # Do not copy keys not in caps. + self.assertNotIn('foobar', self.settings) + + def test_read_empty_settings(self): + # Providing no file should return the default values. + settings = read_settings(None) + expected = copy.deepcopy(DEFAULT_CONFIG) + # Added by configure settings + expected['FEED_DOMAIN'] = '' + expected['ARTICLE_EXCLUDES'] = ['pages'] + expected['PAGE_EXCLUDES'] = [''] + self.maxDiff = None + self.assertDictEqual(settings, expected) + + def test_settings_return_independent(self): + # Make sure that the results from one settings call doesn't + # effect past or future instances. + self.PATH = abspath(dirname(__file__)) + default_conf = join(self.PATH, 'default_conf.py') + settings = read_settings(default_conf) + settings['SITEURL'] = 'new-value' + new_settings = read_settings(default_conf) + self.assertNotEqual(new_settings['SITEURL'], settings['SITEURL']) + + def test_defaults_not_overwritten(self): + # This assumes 'SITENAME': 'A Pelican Blog' + settings = read_settings(None) + settings['SITENAME'] = 'Not a Pelican Blog' + self.assertNotEqual(settings['SITENAME'], DEFAULT_CONFIG['SITENAME']) + + def test_path_settings_safety(self): + """Don't let people setting the static path listings to strs""" + settings = {'STATIC_PATHS': 'foo/bar', + 'THEME_STATIC_PATHS': 'bar/baz', + # These 4 settings are required to run configure_settings + 'PATH': '.', + 'THEME': DEFAULT_THEME, + 'SITEURL': 'http://blog.notmyidea.org/', + 'LOCALE': '', + } + configure_settings(settings) + self.assertEqual(settings['STATIC_PATHS'], + DEFAULT_CONFIG['STATIC_PATHS']) + self.assertEqual(settings['THEME_STATIC_PATHS'], + DEFAULT_CONFIG['THEME_STATIC_PATHS']) + + def test_configure_settings(self): + #Manipulations to settings should be applied correctly. + + settings = { + 'SITEURL': 'http://blog.notmyidea.org/', + 'LOCALE': '', + 'PATH': os.curdir, + 'THEME': DEFAULT_THEME, + } + configure_settings(settings) + # SITEURL should not have a trailing slash + self.assertEqual(settings['SITEURL'], 'http://blog.notmyidea.org') + + # FEED_DOMAIN, if undefined, should default to SITEURL + self.assertEqual(settings['FEED_DOMAIN'], 'http://blog.notmyidea.org') + + settings['FEED_DOMAIN'] = 'http://feeds.example.com' + configure_settings(settings) + self.assertEqual(settings['FEED_DOMAIN'], 'http://feeds.example.com') + + def test_default_encoding(self): + # test that the default locale is set if + # locale is not specified in the settings + + #reset locale to python default + locale.setlocale(locale.LC_ALL, str('C')) + self.assertEqual(self.settings['LOCALE'], DEFAULT_CONFIG['LOCALE']) + + configure_settings(self.settings) + self.assertEqual(locale.getlocale(), locale.getdefaultlocale()) diff --git a/pelican/tests/test_utils.py b/pelican/tests/test_utils.py new file mode 100644 index 00000000..7c9e6e5a --- /dev/null +++ b/pelican/tests/test_utils.py @@ -0,0 +1,544 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function, absolute_import +import logging +import shutil +import os +import time +import locale +from sys import platform, version_info +from tempfile import mkdtemp + +import pytz + +from pelican.generators import TemplatePagesGenerator +from pelican.writers import Writer +from pelican.settings import read_settings +from pelican import utils +from pelican.tests.support import get_article, LoggedTestCase, locale_available, unittest + + +class TestUtils(LoggedTestCase): + _new_attribute = 'new_value' + + @utils.deprecated_attribute( + old='_old_attribute', new='_new_attribute', + since=(3, 1, 0), remove=(4, 1, 3)) + def _old_attribute(): + return None + + def test_deprecated_attribute(self): + value = self._old_attribute + self.assertEqual(value, self._new_attribute) + self.assertLogCountEqual( + count=1, + msg=('_old_attribute has been deprecated since 3.1.0 and will be ' + 'removed by version 4.1.3. Use _new_attribute instead'), + level=logging.WARNING) + + def test_get_date(self): + # valid ones + date = utils.SafeDatetime(year=2012, month=11, day=22) + date_hour = utils.SafeDatetime( + year=2012, month=11, day=22, hour=22, minute=11) + date_hour_z = utils.SafeDatetime( + year=2012, month=11, day=22, hour=22, minute=11, + tzinfo=pytz.timezone('UTC')) + date_hour_est = utils.SafeDatetime( + year=2012, month=11, day=22, hour=22, minute=11, + tzinfo=pytz.timezone('EST')) + date_hour_sec = utils.SafeDatetime( + year=2012, month=11, day=22, hour=22, minute=11, second=10) + date_hour_sec_z = utils.SafeDatetime( + year=2012, month=11, day=22, hour=22, minute=11, second=10, + tzinfo=pytz.timezone('UTC')) + date_hour_sec_est = utils.SafeDatetime( + year=2012, month=11, day=22, hour=22, minute=11, second=10, + tzinfo=pytz.timezone('EST')) + date_hour_sec_frac_z = utils.SafeDatetime( + year=2012, month=11, day=22, hour=22, minute=11, second=10, + microsecond=123000, tzinfo=pytz.timezone('UTC')) + dates = { + '2012-11-22': date, + '2012/11/22': date, + '2012-11-22 22:11': date_hour, + '2012/11/22 22:11': date_hour, + '22-11-2012': date, + '22/11/2012': date, + '22.11.2012': date, + '22.11.2012 22:11': date_hour, + '2012-11-22T22:11Z': date_hour_z, + '2012-11-22T22:11-0500': date_hour_est, + '2012-11-22 22:11:10': date_hour_sec, + '2012-11-22T22:11:10Z': date_hour_sec_z, + '2012-11-22T22:11:10-0500': date_hour_sec_est, + '2012-11-22T22:11:10.123Z': date_hour_sec_frac_z, + } + + # examples from http://www.w3.org/TR/NOTE-datetime + iso_8601_date = utils.SafeDatetime(year=1997, month=7, day=16) + iso_8601_date_hour_tz = utils.SafeDatetime( + year=1997, month=7, day=16, hour=19, minute=20, + tzinfo=pytz.timezone('CET')) + iso_8601_date_hour_sec_tz = utils.SafeDatetime( + year=1997, month=7, day=16, hour=19, minute=20, second=30, + tzinfo=pytz.timezone('CET')) + iso_8601_date_hour_sec_ms_tz = utils.SafeDatetime( + year=1997, month=7, day=16, hour=19, minute=20, second=30, + microsecond=450000, tzinfo=pytz.timezone('CET')) + iso_8601 = { + '1997-07-16': iso_8601_date, + '1997-07-16T19:20+01:00': iso_8601_date_hour_tz, + '1997-07-16T19:20:30+01:00': iso_8601_date_hour_sec_tz, + '1997-07-16T19:20:30.45+01:00': iso_8601_date_hour_sec_ms_tz, + } + + # invalid ones + invalid_dates = ['2010-110-12', 'yay'] + + + for value, expected in dates.items(): + self.assertEqual(utils.get_date(value), expected, value) + + for value, expected in iso_8601.items(): + self.assertEqual(utils.get_date(value), expected, value) + + for item in invalid_dates: + self.assertRaises(ValueError, utils.get_date, item) + + def test_slugify(self): + + samples = (('this is a test', 'this-is-a-test'), + ('this is a test', 'this-is-a-test'), + ('this → is ← a ↑ test', 'this-is-a-test'), + ('this--is---a test', 'this-is-a-test'), + ('unicode測試許功蓋,你看到了嗎?', + 'unicodece-shi-xu-gong-gai-ni-kan-dao-liao-ma'), + ('大飯原発4号機、18日夜起動へ', + 'da-fan-yuan-fa-4hao-ji-18ri-ye-qi-dong-he'),) + + for value, expected in samples: + self.assertEqual(utils.slugify(value), expected) + + def test_slugify_substitute(self): + + samples = (('C++ is based on C', 'cpp-is-based-on-c'), + ('C+++ test C+ test', 'cpp-test-c-test'), + ('c++, c#, C#, C++', 'cpp-c-sharp-c-sharp-cpp'), + ('c++-streams', 'cpp-streams'),) + + subs = (('C++', 'CPP'), ('C#', 'C-SHARP')) + for value, expected in samples: + self.assertEqual(utils.slugify(value, subs), expected) + + def test_get_relative_path(self): + + samples = ((os.path.join('test', 'test.html'), os.pardir), + (os.path.join('test', 'test', 'test.html'), + os.path.join(os.pardir, os.pardir)), + ('test.html', os.curdir), + (os.path.join('/test', 'test.html'), os.pardir), + (os.path.join('/test', 'test', 'test.html'), + os.path.join(os.pardir, os.pardir)), + ('/test.html', os.curdir),) + + for value, expected in samples: + self.assertEqual(utils.get_relative_path(value), expected) + + def test_process_translations(self): + # create a bunch of articles + # 1: no translation metadata + fr_article1 = get_article(lang='fr', slug='yay', title='Un titre', + content='en français') + en_article1 = get_article(lang='en', slug='yay', title='A title', + content='in english') + # 2: reverse which one is the translation thanks to metadata + fr_article2 = get_article(lang='fr', slug='yay2', title='Un titre', + content='en français') + en_article2 = get_article(lang='en', slug='yay2', title='A title', + content='in english', + extra_metadata={'translation': 'true'}) + # 3: back to default language detection if all items have the + # translation metadata + fr_article3 = get_article(lang='fr', slug='yay3', title='Un titre', + content='en français', + extra_metadata={'translation': 'yep'}) + en_article3 = get_article(lang='en', slug='yay3', title='A title', + content='in english', + extra_metadata={'translation': 'yes'}) + + articles = [fr_article1, en_article1, fr_article2, en_article2, + fr_article3, en_article3] + + index, trans = utils.process_translations(articles) + + self.assertIn(en_article1, index) + self.assertIn(fr_article1, trans) + self.assertNotIn(en_article1, trans) + self.assertNotIn(fr_article1, index) + + self.assertIn(fr_article2, index) + self.assertIn(en_article2, trans) + self.assertNotIn(fr_article2, trans) + self.assertNotIn(en_article2, index) + + self.assertIn(en_article3, index) + self.assertIn(fr_article3, trans) + self.assertNotIn(en_article3, trans) + self.assertNotIn(fr_article3, index) + + def test_watchers(self): + # Test if file changes are correctly detected + # Make sure to handle not getting any files correctly. + + dirname = os.path.join(os.path.dirname(__file__), 'content') + folder_watcher = utils.folder_watcher(dirname, ['rst']) + + path = os.path.join(dirname, 'article_with_metadata.rst') + file_watcher = utils.file_watcher(path) + + # first check returns True + self.assertEqual(next(folder_watcher), True) + self.assertEqual(next(file_watcher), True) + + # next check without modification returns False + self.assertEqual(next(folder_watcher), False) + self.assertEqual(next(file_watcher), False) + + # after modification, returns True + t = time.time() + os.utime(path, (t, t)) + self.assertEqual(next(folder_watcher), True) + self.assertEqual(next(file_watcher), True) + + # file watcher with None or empty path should return None + self.assertEqual(next(utils.file_watcher('')), None) + self.assertEqual(next(utils.file_watcher(None)), None) + + empty_path = os.path.join(os.path.dirname(__file__), 'empty') + try: + os.mkdir(empty_path) + os.mkdir(os.path.join(empty_path, "empty_folder")) + shutil.copy(__file__, empty_path) + + # if no files of interest, returns None + watcher = utils.folder_watcher(empty_path, ['rst']) + self.assertEqual(next(watcher), None) + except OSError: + self.fail("OSError Exception in test_files_changed test") + finally: + shutil.rmtree(empty_path, True) + + def test_clean_output_dir(self): + retention = () + test_directory = os.path.join(os.path.dirname(__file__), + 'clean_output') + content = os.path.join(os.path.dirname(__file__), 'content') + shutil.copytree(content, test_directory) + utils.clean_output_dir(test_directory, retention) + self.assertTrue(os.path.isdir(test_directory)) + self.assertListEqual([], os.listdir(test_directory)) + shutil.rmtree(test_directory) + + def test_clean_output_dir_not_there(self): + retention = () + test_directory = os.path.join(os.path.dirname(__file__), + 'does_not_exist') + utils.clean_output_dir(test_directory, retention) + self.assertFalse(os.path.exists(test_directory)) + + def test_clean_output_dir_is_file(self): + retention = () + test_directory = os.path.join(os.path.dirname(__file__), + 'this_is_a_file') + f = open(test_directory, 'w') + f.write('') + f.close() + utils.clean_output_dir(test_directory, retention) + self.assertFalse(os.path.exists(test_directory)) + + def test_strftime(self): + d = utils.SafeDatetime(2012, 8, 29) + + # simple formatting + self.assertEqual(utils.strftime(d, '%d/%m/%y'), '29/08/12') + self.assertEqual(utils.strftime(d, '%d/%m/%Y'), '29/08/2012') + + # RFC 3339 + self.assertEqual(utils.strftime(d, '%Y-%m-%dT%H:%M:%SZ'),'2012-08-29T00:00:00Z') + + # % escaped + self.assertEqual(utils.strftime(d, '%d%%%m%%%y'), '29%08%12') + self.assertEqual(utils.strftime(d, '%d %% %m %% %y'), '29 % 08 % 12') + # not valid % formatter + self.assertEqual(utils.strftime(d, '10% reduction in %Y'), + '10% reduction in 2012') + self.assertEqual(utils.strftime(d, '%10 reduction in %Y'), + '%10 reduction in 2012') + + # with text + self.assertEqual(utils.strftime(d, 'Published in %d-%m-%Y'), + 'Published in 29-08-2012') + + # with non-ascii text + self.assertEqual(utils.strftime(d, '%d/%m/%Y Øl trinken beim Besäufnis'), + '29/08/2012 Øl trinken beim Besäufnis') + + # alternative formatting options + self.assertEqual(utils.strftime(d, '%-d/%-m/%y'), '29/8/12') + self.assertEqual(utils.strftime(d, '%-H:%-M:%-S'), '0:0:0') + + d = utils.SafeDatetime(2012, 8, 9) + self.assertEqual(utils.strftime(d, '%-d/%-m/%y'), '9/8/12') + + + # test the output of utils.strftime in a different locale + # Turkish locale + @unittest.skipUnless(locale_available('tr_TR.UTF-8') or + locale_available('Turkish'), + 'Turkish locale needed') + def test_strftime_locale_dependent_turkish(self): + # store current locale + old_locale = locale.setlocale(locale.LC_TIME) + + if platform == 'win32': + locale.setlocale(locale.LC_TIME, str('Turkish')) + else: + locale.setlocale(locale.LC_TIME, str('tr_TR.UTF-8')) + + d = utils.SafeDatetime(2012, 8, 29) + + # simple + self.assertEqual(utils.strftime(d, '%d %B %Y'), '29 Ağustos 2012') + self.assertEqual(utils.strftime(d, '%A, %d %B %Y'), + 'Çarşamba, 29 Ağustos 2012') + + # with text + self.assertEqual(utils.strftime(d, 'Yayınlanma tarihi: %A, %d %B %Y'), + 'Yayınlanma tarihi: Çarşamba, 29 Ağustos 2012') + + # non-ascii format candidate (someone might pass it... for some reason) + self.assertEqual(utils.strftime(d, '%Y yılında %üretim artışı'), + '2012 yılında %üretim artışı') + + # restore locale back + locale.setlocale(locale.LC_TIME, old_locale) + + + # test the output of utils.strftime in a different locale + # French locale + @unittest.skipUnless(locale_available('fr_FR.UTF-8') or + locale_available('French'), + 'French locale needed') + def test_strftime_locale_dependent_french(self): + # store current locale + old_locale = locale.setlocale(locale.LC_TIME) + + if platform == 'win32': + locale.setlocale(locale.LC_TIME, str('French')) + else: + locale.setlocale(locale.LC_TIME, str('fr_FR.UTF-8')) + + d = utils.SafeDatetime(2012, 8, 29) + + # simple + self.assertEqual(utils.strftime(d, '%d %B %Y'), '29 août 2012') + + # depending on OS, the first letter is m or M + self.assertTrue(utils.strftime(d, '%A') in ('mercredi', 'Mercredi')) + + # with text + self.assertEqual(utils.strftime(d, 'Écrit le %d %B %Y'), + 'Écrit le 29 août 2012') + + # non-ascii format candidate (someone might pass it... for some reason) + self.assertEqual(utils.strftime(d, '%écrits en %Y'), + '%écrits en 2012') + + # restore locale back + locale.setlocale(locale.LC_TIME, old_locale) + + +class TestCopy(unittest.TestCase): + '''Tests the copy utility''' + + def setUp(self): + self.root_dir = mkdtemp(prefix='pelicantests.') + self.old_locale = locale.setlocale(locale.LC_ALL) + locale.setlocale(locale.LC_ALL, str('C')) + + def tearDown(self): + shutil.rmtree(self.root_dir) + locale.setlocale(locale.LC_ALL, self.old_locale) + + def _create_file(self, *path): + with open(os.path.join(self.root_dir, *path), 'w') as f: + f.write('42\n') + + def _create_dir(self, *path): + os.makedirs(os.path.join(self.root_dir, *path)) + + def _exist_file(self, *path): + path = os.path.join(self.root_dir, *path) + self.assertTrue(os.path.isfile(path), 'File does not exist: %s' % path) + + def _exist_dir(self, *path): + path = os.path.join(self.root_dir, *path) + self.assertTrue(os.path.exists(path), + 'Directory does not exist: %s' % path) + + def test_copy_file_same_path(self): + self._create_file('a.txt') + utils.copy(os.path.join(self.root_dir, 'a.txt'), + os.path.join(self.root_dir, 'b.txt')) + self._exist_file('b.txt') + + def test_copy_file_different_path(self): + self._create_dir('a') + self._create_dir('b') + self._create_file('a', 'a.txt') + utils.copy(os.path.join(self.root_dir, 'a', 'a.txt'), + os.path.join(self.root_dir, 'b', 'b.txt')) + self._exist_dir('b') + self._exist_file('b', 'b.txt') + + def test_copy_file_create_dirs(self): + self._create_file('a.txt') + utils.copy(os.path.join(self.root_dir, 'a.txt'), + os.path.join(self.root_dir, 'b0', 'b1', 'b2', 'b3', 'b.txt')) + self._exist_dir('b0') + self._exist_dir('b0', 'b1') + self._exist_dir('b0', 'b1', 'b2') + self._exist_dir('b0', 'b1', 'b2', 'b3') + self._exist_file('b0', 'b1', 'b2', 'b3', 'b.txt') + + def test_copy_dir_same_path(self): + self._create_dir('a') + self._create_file('a', 'a.txt') + utils.copy(os.path.join(self.root_dir, 'a'), + os.path.join(self.root_dir, 'b')) + self._exist_dir('b') + self._exist_file('b', 'a.txt') + + def test_copy_dir_different_path(self): + self._create_dir('a0') + self._create_dir('a0', 'a1') + self._create_file('a0', 'a1', 'a.txt') + self._create_dir('b0') + utils.copy(os.path.join(self.root_dir, 'a0', 'a1'), + os.path.join(self.root_dir, 'b0', 'b1')) + self._exist_dir('b0', 'b1') + self._exist_file('b0', 'b1', 'a.txt') + + def test_copy_dir_create_dirs(self): + self._create_dir('a') + self._create_file('a', 'a.txt') + utils.copy(os.path.join(self.root_dir, 'a'), + os.path.join(self.root_dir, 'b0', 'b1', 'b2', 'b3', 'b')) + self._exist_dir('b0') + self._exist_dir('b0', 'b1') + self._exist_dir('b0', 'b1', 'b2') + self._exist_dir('b0', 'b1', 'b2', 'b3') + self._exist_dir('b0', 'b1', 'b2', 'b3', 'b') + self._exist_file('b0', 'b1', 'b2', 'b3', 'b', 'a.txt') + + +class TestDateFormatter(unittest.TestCase): + '''Tests that the output of DateFormatter jinja filter is same as + utils.strftime''' + + def setUp(self): + # prepare a temp content and output folder + self.temp_content = mkdtemp(prefix='pelicantests.') + self.temp_output = mkdtemp(prefix='pelicantests.') + + # prepare a template file + template_dir = os.path.join(self.temp_content, 'template') + template_path = os.path.join(template_dir, 'source.html') + os.makedirs(template_dir) + with open(template_path, 'w') as template_file: + template_file.write('date = {{ date|strftime("%A, %d %B %Y") }}') + self.date = utils.SafeDatetime(2012, 8, 29) + + + def tearDown(self): + shutil.rmtree(self.temp_content) + shutil.rmtree(self.temp_output) + # reset locale to default + locale.setlocale(locale.LC_ALL, '') + + + @unittest.skipUnless(locale_available('fr_FR.UTF-8') or + locale_available('French'), + 'French locale needed') + def test_french_strftime(self): + # This test tries to reproduce an issue that occurred with python3.3 under macos10 only + locale.setlocale(locale.LC_ALL, str('fr_FR.UTF-8')) + date = utils.SafeDatetime(2014,8,14) + # we compare the lower() dates since macos10 returns "Jeudi" for %A whereas linux reports "jeudi" + self.assertEqual( u'jeudi, 14 août 2014', utils.strftime(date, date_format="%A, %d %B %Y").lower() ) + df = utils.DateFormatter() + self.assertEqual( u'jeudi, 14 août 2014', df(date, date_format="%A, %d %B %Y").lower() ) + # Let us now set the global locale to C: + locale.setlocale(locale.LC_ALL, str('C')) + # DateFormatter should still work as expected since it is the whole point of DateFormatter + # (This is where pre-2014/4/15 code fails on macos10) + df_date = df(date, date_format="%A, %d %B %Y").lower() + self.assertEqual( u'jeudi, 14 août 2014', df_date ) + + + @unittest.skipUnless(locale_available('fr_FR.UTF-8') or + locale_available('French'), + 'French locale needed') + def test_french_locale(self): + settings = read_settings( + override={'LOCALE': locale.normalize('fr_FR.UTF-8'), + 'TEMPLATE_PAGES': {'template/source.html': + 'generated/file.html'}}) + + generator = TemplatePagesGenerator( + {'date': self.date}, settings, + self.temp_content, '', self.temp_output) + generator.env.filters.update({'strftime': utils.DateFormatter()}) + + writer = Writer(self.temp_output, settings=settings) + generator.generate_output(writer) + + output_path = os.path.join( + self.temp_output, 'generated', 'file.html') + + # output file has been generated + self.assertTrue(os.path.exists(output_path)) + + # output content is correct + with utils.pelican_open(output_path) as output_file: + self.assertEqual(output_file, + utils.strftime(self.date, 'date = %A, %d %B %Y')) + + + @unittest.skipUnless(locale_available('tr_TR.UTF-8') or + locale_available('Turkish'), + 'Turkish locale needed') + def test_turkish_locale(self): + settings = read_settings( + override = {'LOCALE': locale.normalize('tr_TR.UTF-8'), + 'TEMPLATE_PAGES': {'template/source.html': + 'generated/file.html'}}) + + generator = TemplatePagesGenerator( + {'date': self.date}, settings, + self.temp_content, '', self.temp_output) + generator.env.filters.update({'strftime': utils.DateFormatter()}) + + writer = Writer(self.temp_output, settings=settings) + generator.generate_output(writer) + + output_path = os.path.join( + self.temp_output, 'generated', 'file.html') + + # output file has been generated + self.assertTrue(os.path.exists(output_path)) + + # output content is correct + with utils.pelican_open(output_path) as output_file: + self.assertEqual(output_file, + utils.strftime(self.date, 'date = %A, %d %B %Y')) diff --git a/pelican/themes/notmyidea/static/css/main.css b/pelican/themes/notmyidea/static/css/main.css index 3d94200b..2efb518d 100644 --- a/pelican/themes/notmyidea/static/css/main.css +++ b/pelican/themes/notmyidea/static/css/main.css @@ -3,15 +3,16 @@ Date: July 2009 Description: Sample layout for HTML5 and CSS3 goodness. Version: 1.0 - Author: Enrique Ramírez - Autor URI: http://enrique-ramirez.com + License: MIT + Licensed by: Smashing Media GmbH + Original author: Enrique Ramírez */ /* Imports */ @import url("reset.css"); @import url("pygment.css"); @import url("typogrify.css"); -@import url(http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz&subset=latin); +@import url(//fonts.googleapis.com/css?family=Yanone+Kaffeesatz&subset=latin); /***** Global *****/ /* Body */ @@ -65,7 +66,9 @@ h1 a:hover { } /* Paragraphs */ -p {margin-bottom: 1.143em;} +div.line-block, +p { margin-top: 1em; + margin-bottom: 1em;} strong, b {font-weight: bold;} em, i {font-style: italic;} @@ -73,14 +76,16 @@ em, i {font-style: italic;} /* Lists */ ul { list-style: outside disc; - margin: 1em 0 1.5em 1.5em; + margin: 0em 0 0 1.5em; } ol { list-style: outside decimal; - margin: 1em 0 1.5em 1.5em; + margin: 0em 0 0 1.5em; } +li { margin-top: 0.5em;} + .post-info { float:right; margin:10px; @@ -88,6 +93,7 @@ ol { } .post-info p{ + margin-top: 1px; margin-bottom: 1px; } @@ -301,15 +307,32 @@ img.left, figure.left {float: left; margin: 0 2em 2em 0;} } /* Icons */ + .social a[href*='about.me'] {background-image: url('../images/icons/aboutme.png');} + .social a[href*='bitbucket.org'] {background-image: url('../images/icons/bitbucket.png');} .social a[href*='delicious.com'] {background-image: url('../images/icons/delicious.png');} .social a[href*='digg.com'] {background-image: url('../images/icons/digg.png');} .social a[href*='facebook.com'] {background-image: url('../images/icons/facebook.png');} - .social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');} - .social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('../images/icons/rss.png');} - .social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');} - .social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');} .social a[href*='gitorious.org'] {background-image: url('../images/icons/gitorious.png');} - .social a[href*='gittip.com'] {background-image: url('../images/icons/gittip.png');} + .social a[href*='github.com'], + .social a[href*='git.io'] { + background-image: url('../images/icons/github.png'); + background-size: 16px 16px; + } + .social a[href*='gittip.com'] {background-image: url('../images/icons/gittip.png');} + .social a[href*='plus.google.com'] {background-image: url('../images/icons/google-plus.png');} + .social a[href*='groups.google.com'] {background-image: url('../images/icons/google-groups.png');} + .social a[href*='news.ycombinator.com'], + .social a[href*='hackernewsers.com'] {background-image: url('../images/icons/hackernews.png');} + .social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');} + .social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');} + .social a[href*='reddit.com'] {background-image: url('../images/icons/reddit.png');} + .social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('../images/icons/rss.png');} + .social a[href*='slideshare.net'] {background-image: url('../images/icons/slideshare.png');} + .social a[href*='speakerdeck.com'] {background-image: url('../images/icons/speakerdeck.png');} + .social a[href*='stackoverflow.com'] {background-image: url('../images/icons/stackoverflow.png');} + .social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');} + .social a[href*='vimeo.com'] {background-image: url('../images/icons/vimeo.png');} + .social a[href*='youtube.com'] {background-image: url('../images/icons/youtube.png');} /* About diff --git a/pelican/themes/notmyidea/static/images/icons/aboutme.png b/pelican/themes/notmyidea/static/images/icons/aboutme.png new file mode 100644 index 00000000..9609df3b Binary files /dev/null and b/pelican/themes/notmyidea/static/images/icons/aboutme.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/bitbucket.png b/pelican/themes/notmyidea/static/images/icons/bitbucket.png new file mode 100644 index 00000000..d05ba161 Binary files /dev/null and b/pelican/themes/notmyidea/static/images/icons/bitbucket.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/delicious.png b/pelican/themes/notmyidea/static/images/icons/delicious.png index c6ce246a..3dccdd84 100644 Binary files a/pelican/themes/notmyidea/static/images/icons/delicious.png and b/pelican/themes/notmyidea/static/images/icons/delicious.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/facebook.png b/pelican/themes/notmyidea/static/images/icons/facebook.png index a7914b49..74e7ad52 100644 Binary files a/pelican/themes/notmyidea/static/images/icons/facebook.png and b/pelican/themes/notmyidea/static/images/icons/facebook.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/github.png b/pelican/themes/notmyidea/static/images/icons/github.png new file mode 100644 index 00000000..8b25551a Binary files /dev/null and b/pelican/themes/notmyidea/static/images/icons/github.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/gitorious.png b/pelican/themes/notmyidea/static/images/icons/gitorious.png index 6485f5ec..3eeb3ece 100644 Binary files a/pelican/themes/notmyidea/static/images/icons/gitorious.png and b/pelican/themes/notmyidea/static/images/icons/gitorious.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/gittip.png b/pelican/themes/notmyidea/static/images/icons/gittip.png index bb12a139..af949625 100644 Binary files a/pelican/themes/notmyidea/static/images/icons/gittip.png and b/pelican/themes/notmyidea/static/images/icons/gittip.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/google-groups.png b/pelican/themes/notmyidea/static/images/icons/google-groups.png new file mode 100644 index 00000000..5de15e68 Binary files /dev/null and b/pelican/themes/notmyidea/static/images/icons/google-groups.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/google-plus.png b/pelican/themes/notmyidea/static/images/icons/google-plus.png new file mode 100644 index 00000000..3c6b7432 Binary files /dev/null and b/pelican/themes/notmyidea/static/images/icons/google-plus.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/hackernews.png b/pelican/themes/notmyidea/static/images/icons/hackernews.png new file mode 100644 index 00000000..fc7a82d4 Binary files /dev/null and b/pelican/themes/notmyidea/static/images/icons/hackernews.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/lastfm.png b/pelican/themes/notmyidea/static/images/icons/lastfm.png index b09c7876..3a6c6262 100644 Binary files a/pelican/themes/notmyidea/static/images/icons/lastfm.png and b/pelican/themes/notmyidea/static/images/icons/lastfm.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/linkedin.png b/pelican/themes/notmyidea/static/images/icons/linkedin.png index feb04962..d29c1201 100644 Binary files a/pelican/themes/notmyidea/static/images/icons/linkedin.png and b/pelican/themes/notmyidea/static/images/icons/linkedin.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/reddit.png b/pelican/themes/notmyidea/static/images/icons/reddit.png new file mode 100644 index 00000000..71ae1215 Binary files /dev/null and b/pelican/themes/notmyidea/static/images/icons/reddit.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/rss.png b/pelican/themes/notmyidea/static/images/icons/rss.png index 7d4e85d9..7862c65a 100644 Binary files a/pelican/themes/notmyidea/static/images/icons/rss.png and b/pelican/themes/notmyidea/static/images/icons/rss.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/slideshare.png b/pelican/themes/notmyidea/static/images/icons/slideshare.png new file mode 100644 index 00000000..ecc97410 Binary files /dev/null and b/pelican/themes/notmyidea/static/images/icons/slideshare.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/speakerdeck.png b/pelican/themes/notmyidea/static/images/icons/speakerdeck.png new file mode 100644 index 00000000..087d0931 Binary files /dev/null and b/pelican/themes/notmyidea/static/images/icons/speakerdeck.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/stackoverflow.png b/pelican/themes/notmyidea/static/images/icons/stackoverflow.png new file mode 100644 index 00000000..f5b65e99 Binary files /dev/null and b/pelican/themes/notmyidea/static/images/icons/stackoverflow.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/twitter.png b/pelican/themes/notmyidea/static/images/icons/twitter.png index d6119280..d0ef3cc1 100644 Binary files a/pelican/themes/notmyidea/static/images/icons/twitter.png and b/pelican/themes/notmyidea/static/images/icons/twitter.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/vimeo.png b/pelican/themes/notmyidea/static/images/icons/vimeo.png new file mode 100644 index 00000000..dba47202 Binary files /dev/null and b/pelican/themes/notmyidea/static/images/icons/vimeo.png differ diff --git a/pelican/themes/notmyidea/static/images/icons/youtube.png b/pelican/themes/notmyidea/static/images/icons/youtube.png new file mode 100644 index 00000000..ce6cbe4f Binary files /dev/null and b/pelican/themes/notmyidea/static/images/icons/youtube.png differ diff --git a/pelican/themes/notmyidea/templates/analytics.html b/pelican/themes/notmyidea/templates/analytics.html index 4de2c86b..e27adf82 100644 --- a/pelican/themes/notmyidea/templates/analytics.html +++ b/pelican/themes/notmyidea/templates/analytics.html @@ -9,4 +9,38 @@ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })(); -{% endif %} \ No newline at end of file +{% endif %} +{% if GAUGES %} + +{% endif %} +{% if PIWIK_URL and PIWIK_SITE_ID %} + +{% endif %} diff --git a/pelican/themes/notmyidea/templates/article.html b/pelican/themes/notmyidea/templates/article.html index fc7e5893..06110b43 100644 --- a/pelican/themes/notmyidea/templates/article.html +++ b/pelican/themes/notmyidea/templates/article.html @@ -5,8 +5,8 @@

    - {{ article.title}}

    + {{ article.title }} {% include 'twitter.html' %}
    @@ -14,18 +14,21 @@ {% include 'article_infos.html' %} {{ article.content }} - {% if DISQUS_SITENAME %} + {% if DISQUS_SITENAME and SITEURL and article.status != "draft" %}

    Comments !

    +
    {% endif %} diff --git a/pelican/themes/notmyidea/templates/article_infos.html b/pelican/themes/notmyidea/templates/article_infos.html index a1993a09..718967e0 100644 --- a/pelican/themes/notmyidea/templates/article_infos.html +++ b/pelican/themes/notmyidea/templates/article_infos.html @@ -1,14 +1,23 @@
    - {{ article.locale_date }} + Published: {{ article.locale_date }} + {% if article.modified %} +
    + + Updated: {{ article.locale_modified }} + + {% endif %} - {% if article.author %} + {% if article.authors %}
    - By {{ article.author }} + By {% for author in article.authors %} + {{ author }} + {% endfor %}
    {% endif %}

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

    {% include 'taglist.html' %} -{% include 'translations.html' %} +{% import 'translations.html' as translations with context %} +{{ translations.translations_for(article) }}
    diff --git a/pelican/themes/notmyidea/templates/authors.html b/pelican/themes/notmyidea/templates/authors.html index e69de29b..e61a332f 100644 --- a/pelican/themes/notmyidea/templates/authors.html +++ b/pelican/themes/notmyidea/templates/authors.html @@ -0,0 +1,16 @@ +{% extends "base.html" %} + +{% block title %}{{ SITENAME }} - Authors{% endblock %} + +{% block content %} + +
    +

    Authors on {{ SITENAME }}

    +
      + {% for author, articles in authors|sort %} +
    • {{ author }} ({{ articles|count }})
    • + {% endfor %} +
    +
    + +{% endblock %} diff --git a/pelican/themes/notmyidea/templates/base.html b/pelican/themes/notmyidea/templates/base.html index 6ab87c5a..d6b4cb35 100644 --- a/pelican/themes/notmyidea/templates/base.html +++ b/pelican/themes/notmyidea/templates/base.html @@ -1,44 +1,39 @@ - + - {% block title %}{{ SITENAME }}{%endblock%} - - {% if FEED_ATOM %} - + {% block title %}{{ SITENAME }}{%endblock%} + + {% if FEED_ALL_ATOM %} + {% endif %} - {% if FEED_RSS %} - + {% if FEED_ALL_RSS %} + {% endif %} - - - - - + + {% include 'github.html' %} {% block content %} @@ -54,13 +49,15 @@ {% endif %} - {% if SOCIAL %} + {% if SOCIAL or FEED_ALL_ATOM or FEED_ALL_RSS %}
      + -You should then also define a CSS style with the appropriate classes (tag-0 to tag-N, where -N matches `TAG_CLOUD_STEPS` -1). +You should then also define CSS styles with appropriate classes (tag-1 to tag-N, +where N matches ``TAG_CLOUD_STEPS``), tag-1 being the most frequent, and +define a ``ul.tagcloud`` class with appropriate list-style to create the cloud. +For example:: + + ul.tagcloud { + list-style: none; + padding: 0; + } + + ul.tagcloud li { + display: inline-block; + } + + li.tag-1 { + font-size: 150%; + } + + li.tag-2 { + font-size: 120%; + } + + ... + Translations ============ -Pelican offers a way to translate articles. See the Getting Started section for +Pelican offers a way to translate articles. See the :doc:`Content ` section for more information. -================================================ ===================================================== -Setting name (default value) What does it do? -================================================ ===================================================== -`DEFAULT_LANG` (``'en'``) The default language to use. -`TRANSLATION_FEED` ('feeds/all-%s.atom.xml'[3]_) Where to put the feed for translations. -================================================ ===================================================== +======================================================== ===================================================== +Setting name (followed by default value, if any) What does it do? +======================================================== ===================================================== +``DEFAULT_LANG = 'en'`` The default language to use. +``TRANSLATION_FEED_ATOM = 'feeds/all-%s.atom.xml'`` [3]_ Where to put the Atom feed for translations. +``TRANSLATION_FEED_RSS = None``, i.e. no RSS Where to put the RSS feed for translations. +======================================================== ===================================================== .. [3] %s is the language + Ordering content -================= +================ ================================================ ===================================================== -Setting name (default value) What does it do? +Setting name (followed by default value) What does it do? ================================================ ===================================================== -`NEWEST_FIRST_ARCHIVES` (``True``) Order archives by newest first by date. (False: +``NEWEST_FIRST_ARCHIVES = True`` Order archives by newest first by date. (False: orders by date with older articles first.) -`REVERSE_CATEGORY_ORDER` (``False``) Reverse the category order. (True: lists by reverse +``REVERSE_CATEGORY_ORDER = False`` Reverse the category order. (True: lists by reverse alphabetical order; default lists alphabetically.) ================================================ ===================================================== + Themes ====== @@ -394,27 +704,32 @@ Creating Pelican themes is addressed in a dedicated section (see :ref:`theming-p However, here are the settings that are related to themes. ================================================ ===================================================== -Setting name (default value) What does it do? +Setting name (followed by default value, if any) What does it do? ================================================ ===================================================== -`THEME` Theme to use to produce the output. Can be a relative +``THEME`` Theme to use to produce the output. Can be a relative or absolute path to a theme folder, or the name of a default theme or a theme installed via ``pelican-themes`` (see below). -`THEME_STATIC_PATHS` (``['static']``) Static theme paths you want to copy. Default +``THEME_STATIC_DIR = 'theme'`` Destination directory in the output path where + Pelican will place the files collected from + `THEME_STATIC_PATHS`. Default is `theme`. +``THEME_STATIC_PATHS = ['static']`` Static theme paths you want to copy. Default value is `static`, but if your theme has - other static paths, you can put them here. -`CSS_FILE` (``'main.css'``) Specify the CSS file you want to load. -`WEBASSETS` (``False``) Asset management with `webassets` (see below) + other static paths, you can put them here. If files + or directories with the same names are included in + the paths defined in this settings, they will be + progressively overwritten. +``CSS_FILE = 'main.css'`` Specify the CSS file you want to load. ================================================ ===================================================== -By default, two themes are available. You can specify them using the `THEME` setting or by passing the -``-t`` option to the ``pelican`` command: +By default, two themes are available. You can specify them using the ``THEME`` +setting or by passing the ``-t`` option to the ``pelican`` command: * notmyidea * simple (a synonym for "plain text" :) -There are a number of other themes available at http://github.com/getpelican/pelican-themes. +There are a number of other themes available at https://github.com/getpelican/pelican-themes. Pelican comes with :doc:`pelican-themes`, a small script for managing themes. You can define your own theme, either by starting from scratch or by duplicating @@ -429,113 +744,149 @@ Following are example ways to specify your preferred theme:: # Specify a customized theme, via path relative to the settings file THEME = "themes/mycustomtheme" # Specify a customized theme, via absolute path - THEME = "~/projects/mysite/themes/mycustomtheme" + THEME = "/home/myuser/projects/mysite/themes/mycustomtheme" -The built-in `notmyidea` theme can make good use of the following settings. Feel +The built-in ``notmyidea`` theme can make good use of the following settings. Feel free to use them in your themes as well. ======================= ======================================================= -Setting name What does it do ? +Setting name What does it do? ======================= ======================================================= -`DISQUS_SITENAME` Pelican can handle Disqus comments. Specify the +``SITESUBTITLE`` A subtitle to appear in the header. +``DISQUS_SITENAME`` Pelican can handle Disqus comments. Specify the Disqus sitename identifier here. -`GITHUB_URL` Your GitHub URL (if you have one). It will then +``GITHUB_URL`` Your GitHub URL (if you have one). It will then use this information to create a GitHub ribbon. -`GOOGLE_ANALYTICS` 'UA-XXXX-YYYY' to activate Google Analytics. -`GOSQUARED_SITENAME` 'XXX-YYYYYY-X' to activate GoSquared. -`MENUITEMS` A list of tuples (Title, URL) for additional menu +``GOOGLE_ANALYTICS`` Set to 'UA-XXXX-YYYY' to activate Google Analytics. +``GOSQUARED_SITENAME`` Set to 'XXX-YYYYYY-X' to activate GoSquared. +``MENUITEMS`` A list of tuples (Title, URL) for additional menu items to appear at the beginning of the main menu. -`PIWIK_URL` URL to your Piwik server - without 'http://' at the +``PIWIK_URL`` URL to your Piwik server - without 'http://' at the beginning. -`PIWIK_SSL_URL` If the SSL-URL differs from the normal Piwik-URL +``PIWIK_SSL_URL`` If the SSL-URL differs from the normal Piwik-URL you have to include this setting too. (optional) -`PIWIK_SITE_ID` ID for the monitored website. You can find the ID - in the Piwik admin interface > settings > websites. -`LINKS` A list of tuples (Title, URL) for links to appear on +``PIWIK_SITE_ID`` ID for the monitored website. You can find the ID + in the Piwik admin interface > Settings > Websites. +``LINKS`` A list of tuples (Title, URL) for links to appear on the header. -`SOCIAL` A list of tuples (Title, URL) to appear in the +``SOCIAL`` A list of tuples (Title, URL) to appear in the "social" section. -`TWITTER_USERNAME` Allows for adding a button to articles to encourage +``TWITTER_USERNAME`` Allows for adding a button to articles to encourage others to tweet about them. Add your Twitter username if you want this button to appear. ======================= ======================================================= -In addition, you can use the "wide" version of the `notmyidea` theme by +In addition, you can use the "wide" version of the ``notmyidea`` theme by adding the following to your configuration:: CSS_FILE = "wide.css" -Asset management ----------------- -The `WEBASSETS` setting allows you to use the `webassets`_ module to manage -assets such as CSS and JS files. The module must first be installed:: +Logging +======= - pip install webassets +Sometimes, a long list of warnings may appear during site generation. Finding +the **meaningful** error message in the middle of tons of annoying log output +can be quite tricky. In order to filter out redundant log messages, Pelican +comes with the ``LOG_FILTER`` setting. -The `webassets` module allows you to perform a number of useful asset management -functions, including: +``LOG_FILTER`` should be a list of tuples ``(level, msg)``, each of them being +composed of the logging level (up to ``warning``) and the message to be ignored. +Simply populate the list with the log messages you want to hide, and they will +be filtered out. -* CSS minifier (`cssmin`, `yuicompressor`, ...) -* CSS compiler (`less`, `sass`, ...) -* JS minifier (`uglifyjs`, `yuicompressor`, `closure`, ...) +For example: ``[(logging.WARN, 'TAG_SAVE_AS is set to False')]`` -Others filters include gzip compression, integration of images in CSS via data -URIs, and more. `webassets` can also append a version identifier to your asset -URL to convince browsers to download new versions of your assets when you use -far-future expires headers. Please refer to the `webassets documentation`_ for -more information. +.. _reading_only_modified_content: -When using with Pelican, `webassets` is configured to process assets in the -``OUTPUT_PATH/theme`` directory. You can use `webassets` in your templates by -including one or more template tags. For example... -.. code-block:: jinja +Reading only modified content +============================= - {% assets filters="cssmin", output="css/style.min.css", "css/inuit.css", "css/pygment-monokai.css", "css/main.css" %} - - {% endassets %} +To speed up the build process, Pelican can optionally read only articles +and pages with modified content. -... will produce a minified css file with a version identifier: +When Pelican is about to read some content source file: -.. code-block:: html +1. The hash or modification time information for the file from a + previous build are loaded from a cache file if ``LOAD_CONTENT_CACHE`` + is ``True``. These files are stored in the ``CACHE_PATH`` + directory. If the file has no record in the cache file, it is read + as usual. +2. The file is checked according to ``CHECK_MODIFIED_METHOD``: - + - If set to ``'mtime'``, the modification time of the file is + checked. + - If set to a name of a function provided by the ``hashlib`` + module, e.g. ``'md5'``, the file hash is checked. + - If set to anything else or the necessary information about the + file cannot be found in the cache file, the content is read as + usual. -These filters can be combined. Here is an example that uses the SASS compiler -and minifies the output: +3. If the file is considered unchanged, the content data saved in a + previous build corresponding to the file is loaded from the cache, + and the file is not read. +4. If the file is considered changed, the file is read and the new + modification information and the content data are saved to the + cache if ``CACHE_CONTENT`` is ``True``. -.. code-block:: jinja +If ``CONTENT_CACHING_LAYER`` is set to ``'reader'`` (the default), +the raw content and metadata returned by a reader are cached. If this +setting is instead set to ``'generator'``, the processed content +object is cached. Caching the processed content object may conflict +with plugins (as some reading related signals may be skipped) and the +``WITH_FUTURE_DATES`` functionality (as the ``draft`` status of the +cached content objects would not change automatically over time). - {% assets filters="sass,cssmin", output="css/style.min.css", "css/style.scss" %} - - {% endassets %} +Checking modification times is faster than comparing file hashes, +but it is not as reliable because ``mtime`` information can be lost, +e.g., when copying content source files using the ``cp`` or ``rsync`` +commands without the ``mtime`` preservation mode (which for ``rsync`` +can be invoked by passing the ``--archive`` flag). -Another example for Javascript: +The cache files are Python pickles, so they may not be readable by +different versions of Python as the pickle format often changes. If +such an error is encountered, the cache files have to be rebuilt by +removing them and re-running Pelican, or by using the Pelican +command-line option ``--ignore-cache``. The cache files also have to +be rebuilt when changing the ``GZIP_CACHE`` setting for cache file +reading to work properly. -.. code-block:: jinja +The ``--ignore-cache`` command-line option is also useful when the +whole cache needs to be regenerated, such as when making modifications +to the settings file that will affect the cached content, or just for +debugging purposes. When Pelican runs in autoreload mode, modification +of the settings file will make it ignore the cache automatically if +``AUTORELOAD_IGNORE_CACHE`` is ``True``. - {% assets filters="uglifyjs,gzip", output="js/packed.js", "js/jquery.js", "js/base.js", "js/widgets.js" %} - - {% endassets %} +Note that even when using cached content, all output is always +written, so the modification times of the generated ``*.html`` files +will always change. Therefore, ``rsync``-based uploading may benefit +from the ``--checksum`` option. -The above will produce a minified and gzipped JS file: +.. _writing_only_selected_content: -.. code-block:: html - +Writing only selected content +============================= -Pelican's debug mode is propagated to `webassets` to disable asset packaging -and instead work with the uncompressed assets. However, this also means that -the LESS and SASS files are not compiled. This should be fixed in a future -version of `webassets` (cf. the related `bug report -`_). +When only working on a single article or page, or making tweaks to +your theme, it is often desirable to generate and review your work +as quickly as possible. In such cases, generating and writing the +entire site output is often unnecessary. By specifying only the +desired files as output paths in the ``WRITE_SELECTED`` list, +**only** those files will be written. This list can be also specified +on the command line using the ``--write-selected`` option, which +accepts a comma-separated list of output file paths. By default this +list is empty, so all output is written. -.. _webassets: https://github.com/miracle2k/webassets -.. _webassets documentation: http://webassets.readthedocs.org/en/latest/builtin_filters.html Example settings ================ .. literalinclude:: ../samples/pelican.conf.py :language: python + + +.. _Jinja custom filters documentation: http://jinja.pocoo.org/docs/api/#custom-filters +.. _Docutils Configuration: http://docutils.sourceforge.net/docs/user/config.html diff --git a/docs/themes.rst b/docs/themes.rst index 7598a28c..c9fc2b37 100644 --- a/docs/themes.rst +++ b/docs/themes.rst @@ -1,13 +1,22 @@ .. _theming-pelican: -How to create themes for Pelican -################################ +Creating themes +############### -Pelican uses the great `Jinja2 `_ templating engine to -generate its HTML output. Jinja2 syntax is really simple. If you want to -create your own theme, feel free to take inspiration from the `"simple" theme +To generate its HTML output, Pelican uses the `Jinja `_ +templating engine due to its flexibility and straightforward syntax. If you want +to create your own theme, feel free to take inspiration from the `"simple" theme `_. +To generate your site using a theme you have created (or downloaded manually and +then modified), you can specify that theme via the ``-t`` flag:: + + pelican content -s pelicanconf.py -t /projects/your-site/themes/your-theme + +If you'd rather not specify the theme on every invocation, you can define +``THEME`` in your settings to point to the location of your preferred theme. + + Structure ========= @@ -17,24 +26,26 @@ To make your own theme, you must follow the following structure:: │   ├── css │   └── images └── templates - ├── archives.html // to display archives - ├── article.html // processed for each article - ├── author.html // processed for each author - ├── authors.html // must list all the authors - ├── categories.html // must list all the categories - ├── category.html // processed for each category - ├── index.html // the index. List all the articles - ├── page.html // processed for each page - ├── tag.html // processed for each tag - └── tags.html // must list all the tags. Can be a tag cloud. + ├── archives.html // to display archives + ├── period_archives.html // to display time-period archives + ├── article.html // processed for each article + ├── author.html // processed for each author + ├── authors.html // must list all the authors + ├── categories.html // must list all the categories + ├── category.html // processed for each category + ├── index.html // the index (list all the articles) + ├── page.html // processed for each page + ├── tag.html // processed for each tag + └── tags.html // must list all the tags. Can be a tag cloud. * `static` contains all the static assets, which will be copied to the output - `theme` folder. I've put the CSS and image folders here, but they are - just examples. Put what you need here. + `theme` folder. The above filesystem layout includes CSS and image folders, + but those are just examples. Put what you need here. * `templates` contains all the templates that will be used to generate the content. - I've just put the mandatory templates here; you can define your own if it helps - you keep things organized while creating your theme. + The template files listed above are mandatory; you can add your own templates + if it helps you keep things organized while creating your theme. + Templates and variables ======================= @@ -43,8 +54,9 @@ The idea is to use a simple syntax that you can embed into your HTML pages. This document describes which templates should exist in a theme, and which variables will be passed to each template at generation time. -All templates will receive the variables defined in your settings file, if they -are in all-caps. You can access them directly. +All templates will receive the variables defined in your settings file, as long +as they are in all-caps. You can access them directly. + Common variables ---------------- @@ -54,95 +66,160 @@ All of these settings will be available to all templates. ============= =================================================== Variable Description ============= =================================================== -articles The list of articles, ordered descending by date +output_file The name of the file currently being generated. For + instance, when Pelican is rendering the home page, + output_file will be "index.html". +articles The list of articles, ordered descending by date. All the elements are `Article` objects, so you can access their attributes (e.g. title, summary, author - etc.) + etc.). Sometimes this is shadowed (for instance in + the tags page). You will then find info about it + in the `all_articles` variable. dates The same list of articles, but ordered by date, - ascending -tags A key-value dict containing the tags (the keys) and - the list of respective articles (the values) -categories A key-value dict containing the categories (keys) - and the list of respective articles (values) + ascending. +tags A list of (tag, articles) tuples, containing all + the tags. +categories A list of (category, articles) tuples, containing + all the categories and corresponding articles (values) pages The list of pages ============= =================================================== + +Sorting +------- + +URL wrappers (currently categories, tags, and authors), have +comparison methods that allow them to be easily sorted by name:: + + {% for tag, articles in tags|sort %} + +If you want to sort based on different criteria, `Jinja's sort +command`__ has a number of options. + +__ http://jinja.pocoo.org/docs/templates/#sort + + +Date Formatting +--------------- + +Pelican formats the date according to your settings and locale +(``DATE_FORMATS``/``DEFAULT_DATE_FORMAT``) and provides a +``locale_date`` attribute. On the other hand, the ``date`` attribute will +be a `datetime`_ object. If you need custom formatting for a date +different than your settings, use the Jinja filter ``strftime`` +that comes with Pelican. Usage is same as Python `strftime`_ format, +but the filter will do the right thing and format your date according +to the locale given in your settings:: + + {{ article.date|strftime('%d %B %Y') }} + +.. _datetime: http://docs.python.org/2/library/datetime.html#datetime-objects +.. _strftime: http://docs.python.org/2/library/datetime.html#strftime-strptime-behavior + + index.html ---------- -This is the home page of your blog, generated at output/index.html. +This is the home page or index of your blog, generated at ``index.html``. -If pagination is active, subsequent pages will reside in output/index`n`.html. +If pagination is active, subsequent pages will reside in ``index{number}.html``. -=================== =================================================== +====================== =================================================== Variable Description -=================== =================================================== +====================== =================================================== articles_paginator A paginator object for the list of articles articles_page The current page of articles +articles_previous_page The previous page of articles (``None`` if page does + not exist) +articles_next_page The next page of articles (``None`` if page does + not exist) dates_paginator A paginator object for the article list, ordered by date, ascending. dates_page The current page of articles, ordered by date, ascending. +dates_previous_page The previous page of articles, ordered by date, + ascending (``None`` if page does not exist) +dates_next_page The next page of articles, ordered by date, + ascending (``None`` if page does not exist) page_name 'index' -- useful for pagination links -=================== =================================================== +====================== =================================================== + author.html ------------- This template will be processed for each of the existing authors, with -output generated at output/author/`author_name`.html. +output generated according to the ``AUTHOR_SAVE_AS`` setting (`Default:` +``author/{author_name}.html``). If pagination is active, subsequent pages will by +default reside at ``author/{author_name}{number}.html``. -If pagination is active, subsequent pages will reside at -output/author/`author_name``n`.html. - -=================== =================================================== +====================== =================================================== Variable Description -=================== =================================================== +====================== =================================================== author The name of the author being processed articles Articles by this author dates Articles by this author, but ordered by date, ascending articles_paginator A paginator object for the list of articles articles_page The current page of articles +articles_previous_page The previous page of articles (``None`` if page does + not exist) +articles_next_page The next page of articles (``None`` if page does + not exist) dates_paginator A paginator object for the article list, ordered by date, ascending. dates_page The current page of articles, ordered by date, ascending. -page_name 'author/`author_name`' -- useful for pagination - links -=================== =================================================== +dates_previous_page The previous page of articles, ordered by date, + ascending (``None`` if page does not exist) +dates_next_page The next page of articles, ordered by date, + ascending (``None`` if page does not exist) +page_name AUTHOR_URL where everything after `{slug}` is + removed -- useful for pagination links +====================== =================================================== + category.html ------------- This template will be processed for each of the existing categories, with -output generated at output/category/`category_name`.html. +output generated according to the ``CATEGORY_SAVE_AS`` setting (`Default:` +``category/{category_name}.html``). If pagination is active, subsequent pages will by +default reside at ``category/{category_name}{number}.html``. -If pagination is active, subsequent pages will reside at -output/category/`category_name``n`.html. - -=================== =================================================== +====================== =================================================== Variable Description -=================== =================================================== +====================== =================================================== category The name of the category being processed articles Articles for this category dates Articles for this category, but ordered by date, ascending articles_paginator A paginator object for the list of articles articles_page The current page of articles +articles_previous_page The previous page of articles (``None`` if page does + not exist) +articles_next_page The next page of articles (``None`` if page does + not exist) dates_paginator A paginator object for the list of articles, ordered by date, ascending dates_page The current page of articles, ordered by date, ascending -page_name 'category/`category_name`' -- useful for pagination - links -=================== =================================================== +dates_previous_page The previous page of articles, ordered by date, + ascending (``None`` if page does not exist) +dates_next_page The next page of articles, ordered by date, + ascending (``None`` if page does not exist) +page_name CATEGORY_URL where everything after `{slug}` is + removed -- useful for pagination links +====================== =================================================== + article.html ------------- -This template will be processed for each article, with .html files saved -as output/`article_name`.html. Here are the specific variables it gets. +This template will be processed for each article, with +output generated according to the ``ARTICLE_SAVE_AS`` setting (`Default:` +``{article_name}.html``). The following variables are available when +rendering. ============= =================================================== Variable Description @@ -151,11 +228,39 @@ article The article object to be displayed category The name of the category for the current article ============= =================================================== +Any metadata that you put in the header of the article source file +will be available as fields on the ``article`` object. The field name will be +the same as the name of the metadata field, except in all-lowercase characters. + +For example, you could add a field called `FacebookImage` to your article +metadata, as shown below: + +.. code-block:: markdown + + Title: I love Python more than music + Date: 2013-11-06 10:06 + Tags: personal, python + Category: Tech + Slug: python-je-l-aime-a-mourir + Author: Francis Cabrel + FacebookImage: http://franciscabrel.com/images/pythonlove.png + +This new metadata will be made available as `article.facebookimage` in your +`article.html` template. This would allow you, for example, to specify an +image for the Facebook open graph tags that will change for each article: + +.. code-block:: html+jinja + + + + page.html --------- -This template will be processed for each page, with corresponding .html files -saved as output/`page_name`.html. +This template will be processed for each page, with +output generated according to the ``PAGE_SAVE_AS`` setting (`Default:` +``pages/{page_name}.html``). The following variables are available when +rendering. ============= =================================================== Variable Description @@ -164,30 +269,64 @@ page The page object to be displayed. You can access its title, slug, and content. ============= =================================================== + tag.html -------- -This template will be processed for each tag, with corresponding .html files -saved as output/tag/`tag_name`.html. +This template will be processed for each tag, with +output generated according to the ``TAG_SAVE_AS`` setting (`Default:` +``tag/{tag_name}.html``). If pagination is active, subsequent pages will by +default reside at ``tag/{tag_name}{number}.html``. -If pagination is active, subsequent pages will reside at -output/tag/`tag_name``n`.html. - -=================== =================================================== +====================== =================================================== Variable Description -=================== =================================================== +====================== =================================================== tag The name of the tag being processed articles Articles related to this tag dates Articles related to this tag, but ordered by date, ascending articles_paginator A paginator object for the list of articles articles_page The current page of articles +articles_previous_page The previous page of articles (``None`` if page does + not exist) +articles_next_page The next page of articles (``None`` if page does + not exist) dates_paginator A paginator object for the list of articles, ordered by date, ascending dates_page The current page of articles, ordered by date, ascending -page_name 'tag/`tag_name`' -- useful for pagination links +dates_previous_page The previous page of articles, ordered by date, + ascending (``None`` if page does not exist) +dates_next_page The next page of articles, ordered by date, + ascending (``None`` if page does not exist) +page_name TAG_URL where everything after `{slug}` is removed + -- useful for pagination links +====================== =================================================== + + +period_archives.html +-------------------- + +This template will be processed for each year of your posts if a path +for ``YEAR_ARCHIVE_SAVE_AS`` is defined, each month if ``MONTH_ARCHIVE_SAVE_AS`` +is defined, and each day if ``DAY_ARCHIVE_SAVE_AS`` is defined. + =================== =================================================== +Variable Description +=================== =================================================== +period A tuple of the form (`year`, `month`, `day`) that + indicates the current time period. `year` and `day` + are numbers while `month` is a string. This tuple + only contains `year` if the time period is a + given year. It contains both `year` and `month` + if the time period is over years and months and + so on. + +=================== =================================================== + +You can see an example of how to use `period` in the `"simple" theme +`_. + Feeds ===== @@ -198,11 +337,14 @@ Here is a complete list of the feed variables:: FEED_ATOM FEED_RSS + FEED_ALL_ATOM + FEED_ALL_RSS CATEGORY_FEED_ATOM CATEGORY_FEED_RSS TAG_FEED_ATOM TAG_FEED_RSS - TRANSLATION_FEED + TRANSLATION_FEED_ATOM + TRANSLATION_FEED_RSS Inheritance @@ -216,7 +358,8 @@ missing, it will be replaced by the matching template from the ``simple`` theme. So if the HTML structure of a template in the ``simple`` theme is right for you, you don't have to write a new template from scratch. -You can also extend templates from the ``simple`` themes in your own themes by using the ``{% extends %}`` directive as in the following example: +You can also extend templates from the ``simple`` theme in your own themes by +using the ``{% extends %}`` directive as in the following example: .. code-block:: html+jinja @@ -244,14 +387,17 @@ The first file is the ``templates/base.html`` template: {% endblock %} +1. On the first line, we extend the ``base.html`` template from the ``simple`` + theme, so we don't have to rewrite the entire file. +2. On the third line, we open the ``head`` block which has already been defined + in the ``simple`` theme. +3. On the fourth line, the function ``super()`` keeps the content previously + inserted in the ``head`` block. +4. On the fifth line, we append a stylesheet to the page. +5. On the last line, we close the ``head`` block. -1. On the first line, we extend the ``base.html`` template from the ``simple`` theme, so we don't have to rewrite the entire file. -2. On the third line, we open the ``head`` block which has already been defined in the ``simple`` theme. -3. On the fourth line, the function ``super()`` keeps the content previously inserted in the ``head`` block. -4. On the fifth line, we append a stylesheet to the page. -5. On the last line, we close the ``head`` block. - -This file will be extended by all the other templates, so the stylesheet will be linked from all pages. +This file will be extended by all the other templates, so the stylesheet will +be linked from all pages. style.css """"""""" diff --git a/docs/tips.rst b/docs/tips.rst index abb739b1..eb400124 100644 --- a/docs/tips.rst +++ b/docs/tips.rst @@ -6,47 +6,96 @@ Here are some tips about Pelican that you might find useful. Publishing to GitHub ==================== -GitHub comes with an interesting "pages" feature: you can upload things there -and it will be available directly from their servers. As Pelican is a static -file generator, we can take advantage of this. - -User Pages ----------- -GitHub allows you to create user pages in the form of ``username.github.com``. -Whatever is created in the master branch will be published. For this purpose, -just the output generated by Pelican needs to pushed to GitHub. - -So given a repository containing your articles, just run Pelican over the posts -and deploy the master branch to GitHub:: - - $ pelican -s pelican.conf.py ./path/to/posts -o /path/to/output - -Now add all the files in the output directory generated by Pelican:: - - $ git add /path/to/output/* - $ git commit -am "Your Message" - $ git push origin master +`GitHub Pages `_ offer an easy +and convenient way to publish Pelican sites. There are `two types of GitHub +Pages `_: +*Project Pages* and *User Pages*. Pelican sites can be published as both +Project Pages and User Pages. Project Pages ------------- -For creating Project pages, a branch called ``gh-pages`` is used for publishing. -The excellent `ghp-import `_ makes this -really easy, which can be installed via:: - $ pip install ghp-import +To publish a Pelican site as a Project Page you need to *push* the content of +the ``output`` dir generated by Pelican to a repository's ``gh-pages`` branch +on GitHub. -Then, given a repository containing your articles, you would simply run -Pelican and upload the output to GitHub:: +The excellent `ghp-import `_, which can +be installed with ``easy_install`` or ``pip``, makes this process really easy. - $ pelican -s pelican.conf.py . +For example, if the source of your Pelican site is contained in a GitHub +repository, and if you want to publish that Pelican site in the form of Project +Pages to this repository, you can then use the following:: + + $ pelican content -o output -s pelicanconf.py $ ghp-import output $ git push origin gh-pages -And that's it. +The ``ghp-import output`` command updates the local ``gh-pages`` branch with +the content of the ``output`` directory (creating the branch if it doesn't +already exist). The ``git push origin gh-pages`` command updates the remote +``gh-pages`` branch, effectively publishing the Pelican site. -If you want, you can put that directly into a post-commit hook, so each time you -commit, your blog is up-to-date on GitHub! +.. note:: -Put the following into ``.git/hooks/post-commit``:: + The ``github`` target of the Makefile created by the ``pelican-quickstart`` + command publishes the Pelican site as Project Pages, as described above. - pelican -s pelican.conf.py . && ghp-import output && git push origin gh-pages +User Pages +---------- + +To publish a Pelican site in the form of User Pages, you need to *push* the +content of the ``output`` dir generated by Pelican to the ``master`` branch of +your ``.github.io`` repository on GitHub. + +Again, you can take advantage of ``ghp-import``:: + + $ pelican content -o output -s pelicanconf.py + $ ghp-import output + $ git push git@github.com:elemoine/elemoine.github.io.git gh-pages:master + +The ``git push`` command pushes the local ``gh-pages`` branch (freshly updated +by the ``ghp-import`` command) to the ``elemoine.github.io`` repository's +``master`` branch on GitHub. + +.. note:: + + To publish your Pelican site as User Pages, feel free to adjust the + ``github`` target of the Makefile. + +Extra Tips +---------- + +Tip #1: + +To automatically update your Pelican site on each commit, you can create +a post-commit hook. For example, you can add the following to +``.git/hooks/post-commit``:: + + pelican content -o output -s pelicanconf.py && ghp-import output && git push origin gh-pages + +Tip #2: + +To use a `custom domain +`_ with +GitHub Pages, you need to put the domain of your site (e.g., +``blog.example.com``) inside a ``CNAME`` file at the root of your site. To do +this, create the ``content/extra/`` directory and add a ``CNAME`` file to it. +Then use the ``STATIC_PATHS`` setting to tell Pelican to copy this file to your +output directory. For example:: + + STATIC_PATHS = ['images', 'extra/CNAME'] + EXTRA_PATH_METADATA = {'extra/CNAME': {'path': 'CNAME'},} + +How to add YouTube or Vimeo Videos +================================== + +The easiest way is to paste the embed code of the video from these sites +directly into your source content. + +Alternatively, you can also use Pelican plugins like ``liquid_tags``, +``pelican_youtube``, or ``pelican_vimeo`` to embed videos in your content. + +Moreover, markup languages like reST and Markdown have plugins that let you +embed videos in the markup. You can use `reST video directive +`_ for reST or `mdx_video plugin +`_ for Markdown. diff --git a/pelican/__init__.py b/pelican/__init__.py index 9bcac779..967360c9 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -1,94 +1,96 @@ -import copy +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function +import six + import os import re import sys import time import logging import argparse +import locale +import collections + +# pelican.log has to be the first pelican module to be loaded +# because logging.setLoggerClass has to be called before logging.getLogger +from pelican.log import init from pelican import signals from pelican.generators import (ArticlesGenerator, PagesGenerator, - StaticGenerator, PdfGenerator, - LessCSSGenerator, SourceFileGenerator) -from pelican.log import init -from pelican.settings import read_settings, _DEFAULT_CONFIG -from pelican.utils import (clean_output_dir, files_changed, file_changed, - NoFilesError) + StaticGenerator, SourceFileGenerator, + TemplatePagesGenerator) +from pelican.readers import Readers +from pelican.settings import read_settings +from pelican.utils import clean_output_dir, folder_watcher, file_watcher from pelican.writers import Writer -__major__ = 3 -__minor__ = 0 -__version__ = "{0}.{1}".format(__major__, __minor__) +__version__ = "3.5.0" + +DEFAULT_CONFIG_NAME = 'pelicanconf.py' logger = logging.getLogger(__name__) class Pelican(object): - def __init__(self, settings=None, path=None, theme=None, output_path=None, - markup=None, delete_outputdir=False, plugin_path=None): - """Read the settings, and performs some checks on the environment - before doing anything else. + + def __init__(self, settings): + """ + Pelican initialisation, performs some checks on the environment before + doing anything else. """ - if settings is None: - settings = copy.deepcopy(_DEFAULT_CONFIG) - - self.path = path or settings['PATH'] - if not self.path: - raise Exception('You need to specify a path containing the content' - ' (see pelican --help for more information)') - - if self.path.endswith('/'): - self.path = self.path[:-1] # define the default settings self.settings = settings - self._handle_deprecation() - self.theme = theme or settings['THEME'] - output_path = output_path or settings['OUTPUT_PATH'] - self.output_path = os.path.realpath(output_path) - self.markup = markup or settings['MARKUP'] - self.delete_outputdir = delete_outputdir \ - or settings['DELETE_OUTPUT_DIRECTORY'] - - # find the theme in pelican.theme if the given one does not exists - if not os.path.exists(self.theme): - theme_path = os.sep.join([os.path.dirname( - os.path.abspath(__file__)), "themes/%s" % self.theme]) - if os.path.exists(theme_path): - self.theme = theme_path - else: - raise Exception("Impossible to find the theme %s" % theme) + self.path = settings['PATH'] + self.theme = settings['THEME'] + self.output_path = settings['OUTPUT_PATH'] + self.ignore_files = settings['IGNORE_FILES'] + self.delete_outputdir = settings['DELETE_OUTPUT_DIRECTORY'] + self.output_retention = settings['OUTPUT_RETENTION'] self.init_path() self.init_plugins() signals.initialized.send(self) def init_path(self): - if not any(p in sys.path for p in ['', '.']): + if not any(p in sys.path for p in ['', os.curdir]): logger.debug("Adding current directory to system path") sys.path.insert(0, '') def init_plugins(self): - self.plugins = self.settings['PLUGINS'] - for plugin in self.plugins: + self.plugins = [] + logger.debug('Temporarily adding PLUGIN_PATHS to system path') + _sys_path = sys.path[:] + for pluginpath in self.settings['PLUGIN_PATHS']: + sys.path.insert(0, pluginpath) + for plugin in self.settings['PLUGINS']: # if it's a string, then import it - if isinstance(plugin, basestring): - logger.debug("Loading plugin `{0}' ...".format(plugin)) - plugin = __import__(plugin, globals(), locals(), 'module') + if isinstance(plugin, six.string_types): + logger.debug("Loading plugin `%s`", plugin) + try: + plugin = __import__(plugin, globals(), locals(), + str('module')) + except ImportError as e: + logger.error( + "Cannot load plugin `%s`\n%s", plugin, e) + continue - logger.debug("Registering plugin `{0}'".format(plugin.__name__)) + logger.debug("Registering plugin `%s`", plugin.__name__) plugin.register() + self.plugins.append(plugin) + logger.debug('Restoring system path') + sys.path = _sys_path def _handle_deprecation(self): if self.settings.get('CLEAN_URLS', False): logger.warning('Found deprecated `CLEAN_URLS` in settings.' - ' Modifying the following settings for the' - ' same behaviour.') + ' Modifying the following settings for the' + ' same behaviour.') self.settings['ARTICLE_URL'] = '{slug}/' self.settings['ARTICLE_LANG_URL'] = '{slug}-{lang}/' @@ -97,12 +99,12 @@ class Pelican(object): for setting in ('ARTICLE_URL', 'ARTICLE_LANG_URL', 'PAGE_URL', 'PAGE_LANG_URL'): - logger.warning("%s = '%s'" % (setting, self.settings[setting])) + logger.warning("%s = '%s'", setting, self.settings[setting]) if self.settings.get('ARTICLE_PERMALINK_STRUCTURE', False): logger.warning('Found deprecated `ARTICLE_PERMALINK_STRUCTURE` in' - ' settings. Modifying the following settings for' - ' the same behaviour.') + ' settings. Modifying the following settings for' + ' the same behaviour.') structure = self.settings['ARTICLE_PERMALINK_STRUCTURE'] @@ -116,175 +118,259 @@ class Pelican(object): 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'): + 'PAGE_LANG_URL', 'DRAFT_URL', 'DRAFT_LANG_URL', + 'ARTICLE_SAVE_AS', 'ARTICLE_LANG_SAVE_AS', + 'DRAFT_SAVE_AS', 'DRAFT_LANG_SAVE_AS', + 'PAGE_SAVE_AS', 'PAGE_LANG_SAVE_AS'): self.settings[setting] = os.path.join(structure, self.settings[setting]) - logger.warning("%s = '%s'" % (setting, self.settings[setting])) + logger.warning("%s = '%s'", setting, self.settings[setting]) - if self.settings.get('FEED', False): - logger.warning('Found deprecated `FEED` in settings. Modify FEED' - ' to FEED_ATOM in your settings and theme for the same behavior.' - ' Temporarily setting FEED_ATOM for backwards compatibility.') - self.settings['FEED_ATOM'] = self.settings['FEED'] - - if self.settings.get('TAG_FEED', False): - logger.warning('Found deprecated `TAG_FEED` in settings. Modify ' - ' TAG_FEED to TAG_FEED_ATOM in your settings and theme for the ' - 'same behavior. Temporarily setting TAG_FEED_ATOM for backwards ' - 'compatibility.') - self.settings['TAG_FEED_ATOM'] = self.settings['TAG_FEED'] - - if self.settings.get('CATEGORY_FEED', False): - logger.warning('Found deprecated `CATEGORY_FEED` in settings. ' - 'Modify CATEGORY_FEED to CATEGORY_FEED_ATOM in your settings and ' - 'theme for the same behavior. Temporarily setting ' - 'CATEGORY_FEED_ATOM for backwards compatibility.') - self.settings['CATEGORY_FEED_ATOM'] =\ - self.settings['CATEGORY_FEED'] + for new, old in [('FEED', 'FEED_ATOM'), ('TAG_FEED', 'TAG_FEED_ATOM'), + ('CATEGORY_FEED', 'CATEGORY_FEED_ATOM'), + ('TRANSLATION_FEED', 'TRANSLATION_FEED_ATOM')]: + if self.settings.get(new, False): + logger.warning( + 'Found deprecated `%(new)s` in settings. Modify %(new)s ' + 'to %(old)s in your settings and theme for the same ' + 'behavior. Temporarily setting %(old)s for backwards ' + 'compatibility.', + {'new': new, 'old': old} + ) + self.settings[old] = self.settings[new] def run(self): """Run the generators and return""" + start_time = time.time() context = self.settings.copy() + # Share these among all the generators and content objects: + context['filenames'] = {} # maps source path to Content object or None + context['localsiteurl'] = self.settings['SITEURL'] + generators = [ cls( - context, - self.settings, - self.path, - self.theme, - self.output_path, - self.markup, - self.delete_outputdir + context=context, + settings=self.settings, + path=self.path, + theme=self.theme, + output_path=self.output_path, ) for cls in self.get_generator_classes() ] + # erase the directory if it is not the source and if that's + # explicitly asked + if (self.delete_outputdir and not + os.path.realpath(self.path).startswith(self.output_path)): + clean_output_dir(self.output_path, self.output_retention) + for p in generators: if hasattr(p, 'generate_context'): p.generate_context() - # erase the directory if it is not the source and if that's - # explicitely asked - if (self.delete_outputdir and not - os.path.realpath(self.path).startswith(self.output_path)): - clean_output_dir(self.output_path) - writer = self.get_writer() - # pass the assets environment to the generators - if self.settings['WEBASSETS']: - generators[1].env.assets_environment = generators[0].assets_env - generators[2].env.assets_environment = generators[0].assets_env - for p in generators: if hasattr(p, 'generate_output'): p.generate_output(writer) signals.finalized.send(self) + articles_generator = next(g for g in generators + if isinstance(g, ArticlesGenerator)) + pages_generator = next(g for g in generators + if isinstance(g, PagesGenerator)) + + print('Done: Processed {} article(s), {} draft(s) and {} page(s) in ' \ + '{:.2f} seconds.'.format( + len(articles_generator.articles) + len(articles_generator.translations), + len(articles_generator.drafts) + \ + len(articles_generator.drafts_translations), + len(pages_generator.pages) + len(pages_generator.translations), + time.time() - start_time)) + def get_generator_classes(self): - generators = [StaticGenerator, ArticlesGenerator, PagesGenerator] - if self.settings['PDF_GENERATOR']: - generators.append(PdfGenerator) - if self.settings['LESS_GENERATOR']: # can be True or PATH to lessc - generators.append(LessCSSGenerator) + generators = [ArticlesGenerator, PagesGenerator] + + if self.settings['TEMPLATE_PAGES']: + generators.append(TemplatePagesGenerator) if self.settings['OUTPUT_SOURCES']: generators.append(SourceFileGenerator) for pair in signals.get_generators.send(self): (funct, value) = pair - if not isinstance(value, (tuple, list)): + if not isinstance(value, collections.Iterable): value = (value, ) for v in value: if isinstance(v, type): - logger.debug('Found generator: {0}'.format(v)) + logger.debug('Found generator: %s', v) generators.append(v) + # StaticGenerator must run last, so it can identify files that + # were skipped by the other generators, and so static files can + # have their output paths overridden by the {attach} link syntax. + generators.append(StaticGenerator) return generators def get_writer(self): - return Writer(self.output_path, settings=self.settings) + writers = [ w for (_, w) in signals.get_writer.send(self) + if isinstance(w, type) ] + writers_found = len(writers) + if writers_found == 0: + return Writer(self.output_path, settings=self.settings) + else: + writer = writers[0] + if writers_found == 1: + logger.debug('Found writer: %s', writer) + else: + logger.warning( + '%s writers found, using only first one: %s', + writers_found, writer) + return writer(self.output_path, settings=self.settings) def parse_arguments(): - parser = argparse.ArgumentParser(description="""A tool to generate a - static blog, with restructured text input files.""", - formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser = argparse.ArgumentParser( + description="""A tool to generate a static blog, + with restructured text input files.""", + formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) parser.add_argument(dest='path', nargs='?', - help='Path where to find the content files.', - default=None) + help='Path where to find the content files.', + default=None) parser.add_argument('-t', '--theme-path', dest='theme', - help='Path where to find the theme templates. If not specified, it' - 'will use the default one included with pelican.') + help='Path where to find the theme templates. If not ' + 'specified, it will use the default one included with ' + 'pelican.') parser.add_argument('-o', '--output', dest='output', - help='Where to output the generated files. If not specified, a ' - 'directory will be created, named "output" in the current path.') - - parser.add_argument('-m', '--markup', dest='markup', - help='The list of markup language to use (rst or md). Please indicate ' - 'them separated by commas.') + help='Where to output the generated files. If not ' + 'specified, a directory will be created, named ' + '"output" in the current path.') parser.add_argument('-s', '--settings', dest='settings', - help='The settings of the application.') + help='The settings of the application, this is ' + 'automatically set to {0} if a file exists with this ' + 'name.'.format(DEFAULT_CONFIG_NAME)) parser.add_argument('-d', '--delete-output-directory', - dest='delete_outputdir', - action='store_true', help='Delete the output directory.') + dest='delete_outputdir', action='store_true', + default=None, help='Delete the output directory.') parser.add_argument('-v', '--verbose', action='store_const', - const=logging.INFO, dest='verbosity', - help='Show all messages.') + const=logging.INFO, dest='verbosity', + help='Show all messages.') parser.add_argument('-q', '--quiet', action='store_const', - const=logging.CRITICAL, dest='verbosity', - help='Show only critical errors.') + const=logging.CRITICAL, dest='verbosity', + help='Show only critical errors.') parser.add_argument('-D', '--debug', action='store_const', - const=logging.DEBUG, dest='verbosity', - help='Show all message, including debug messages.') + const=logging.DEBUG, dest='verbosity', + help='Show all messages, including debug messages.') parser.add_argument('--version', action='version', version=__version__, - help='Print the pelican version and exit.') + help='Print the pelican version and exit.') parser.add_argument('-r', '--autoreload', dest='autoreload', - action='store_true', - help="Relaunch pelican each time a modification occurs" - " on the content files.") + action='store_true', + help='Relaunch pelican each time a modification occurs' + ' on the content files.') + + parser.add_argument('--cache-path', dest='cache_path', + help=('Directory in which to store cache files. ' + 'If not specified, defaults to "cache".')) + + parser.add_argument('--ignore-cache', action='store_true', + dest='ignore_cache', help='Ignore content cache ' + 'from previous runs by not loading cache files.') + + parser.add_argument('-w', '--write-selected', type=str, + dest='selected_paths', default=None, + help='Comma separated list of selected paths to write') + return parser.parse_args() +def get_config(args): + config = {} + if args.path: + config['PATH'] = os.path.abspath(os.path.expanduser(args.path)) + if args.output: + config['OUTPUT_PATH'] = \ + os.path.abspath(os.path.expanduser(args.output)) + if args.theme: + abstheme = os.path.abspath(os.path.expanduser(args.theme)) + config['THEME'] = abstheme if os.path.exists(abstheme) else args.theme + if args.delete_outputdir is not None: + config['DELETE_OUTPUT_DIRECTORY'] = args.delete_outputdir + if args.ignore_cache: + config['LOAD_CONTENT_CACHE'] = False + if args.cache_path: + config['CACHE_PATH'] = args.cache_path + if args.selected_paths: + config['WRITE_SELECTED'] = args.selected_paths.split(',') + config['DEBUG'] = args.verbosity == logging.DEBUG + + # argparse returns bytes in Py2. There is no definite answer as to which + # encoding argparse (or sys.argv) uses. + # "Best" option seems to be locale.getpreferredencoding() + # ref: http://mail.python.org/pipermail/python-list/2006-October/405766.html + if not six.PY3: + enc = locale.getpreferredencoding() + for key in config: + if key in ('PATH', 'OUTPUT_PATH', 'THEME'): + config[key] = config[key].decode(enc) + return config + + def get_instance(args): - markup = [a.strip().lower() for a in args.markup.split(',')]\ - if args.markup else None - settings = read_settings(args.settings) + config_file = args.settings + if config_file is None and os.path.isfile(DEFAULT_CONFIG_NAME): + config_file = DEFAULT_CONFIG_NAME - cls = settings.get('PELICAN_CLASS') - if isinstance(cls, basestring): + settings = read_settings(config_file, override=get_config(args)) + + cls = settings['PELICAN_CLASS'] + if isinstance(cls, six.string_types): module, cls_name = cls.rsplit('.', 1) module = __import__(module) cls = getattr(module, cls_name) - return cls(settings, args.path, args.theme, args.output, markup, - args.delete_outputdir) + return cls(settings), settings def main(): args = parse_arguments() init(args.verbosity) - # Split the markup languages only if some have been given. Otherwise, - # populate the variable with None. - pelican = get_instance(args) + pelican, settings = get_instance(args) + readers = Readers(settings) + + watchers = {'content': folder_watcher(pelican.path, + readers.extensions, + pelican.ignore_files), + 'theme': folder_watcher(pelican.theme, + [''], + pelican.ignore_files), + 'settings': file_watcher(args.settings)} + + for static_path in settings.get("STATIC_PATHS", []): + watchers[static_path] = folder_watcher(static_path, [''], pelican.ignore_files) try: if args.autoreload: - files_found_error = True + print(' --- AutoReload Mode: Monitoring `content`, `theme` and' + ' `settings` for changes. ---') + + def _ignore_cache(pelican_obj): + if pelican_obj.settings['AUTORELOAD_IGNORE_CACHE']: + pelican_obj.settings['LOAD_CONTENT_CACHE'] = False + while True: try: # Check source dir for changed files ending with the given @@ -292,40 +378,56 @@ def main(): # restriction; all files are recursively checked if they # have changed, no matter what extension the filenames # have. - if files_changed(pelican.path, pelican.markup) or \ - files_changed(pelican.theme, ['']): - if not files_found_error: - files_found_error = True - pelican.run() + modified = {k: next(v) for k, v in watchers.items()} + original_load_cache = settings['LOAD_CONTENT_CACHE'] - # reload also if settings.py changed - if file_changed(args.settings): - logger.info('%s changed, re-generating' % - args.settings) - pelican = get_instance(args) - pelican.run() + if modified['settings']: + pelican, settings = get_instance(args) + original_load_cache = settings['LOAD_CONTENT_CACHE'] + _ignore_cache(pelican) + + if any(modified.values()): + print('\n-> Modified: {}. re-generating...'.format( + ', '.join(k for k, v in modified.items() if v))) + + if modified['content'] is None: + logger.warning('No valid files found in content.') + + if modified['theme'] is None: + logger.warning('Empty theme folder. Using `basic` ' + 'theme.') + + pelican.run() + # restore original caching policy + pelican.settings['LOAD_CONTENT_CACHE'] = original_load_cache - time.sleep(.5) # sleep to avoid cpu load except KeyboardInterrupt: logger.warning("Keyboard interrupt, quitting.") break - except NoFilesError: - if files_found_error: - logger.warning("No valid files found in content. " - "Nothing to generate.") - files_found_error = False - time.sleep(1) # sleep to avoid cpu load - except Exception, e: - logger.warning( - "Caught exception \"{}\". Reloading.".format(e) - ) - continue - else: - pelican.run() - except Exception, e: - logger.critical(unicode(e)) - if (args.verbosity == logging.DEBUG): + except Exception as e: + if (args.verbosity == logging.DEBUG): + logger.critical(e.args) + raise + logger.warning( + 'Caught exception "%s". Reloading.', e) + + finally: + time.sleep(.5) # sleep to avoid cpu load + + else: + if next(watchers['content']) is None: + logger.warning('No valid files found in content.') + + if next(watchers['theme']) is None: + logger.warning('Empty theme folder. Using `basic` theme.') + + pelican.run() + + except Exception as e: + logger.critical('%s', e) + + if args.verbosity == logging.DEBUG: raise else: sys.exit(getattr(e, 'exitcode', 1)) diff --git a/pelican/contents.py b/pelican/contents.py index b5701732..beff2106 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -1,46 +1,64 @@ # -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function +import six +from six.moves.urllib.parse import (unquote, urlparse, urlunparse) + import copy import locale import logging import functools - -from datetime import datetime -from os import getenv -from sys import platform, stdin +import os +import re +import sys -from pelican.settings import _DEFAULT_CONFIG -from pelican.utils import slugify, truncate_html_words from pelican import signals +from pelican.settings import DEFAULT_CONFIG +from pelican.utils import (slugify, truncate_html_words, memoized, strftime, + python_2_unicode_compatible, deprecated_attribute, + path_to_url, set_date_tzinfo, SafeDatetime) + +# Import these so that they're avalaible when you import from pelican.contents. +from pelican.urlwrappers import (URLWrapper, Author, Category, Tag) # NOQA logger = logging.getLogger(__name__) -class Page(object): - """Represents a page - Given a content, and metadata, create an adequate object. + +class Content(object): + """Represents a content. :param content: the string to parse, containing the original content. + :param metadata: the metadata associated to this page (optional). + :param settings: the settings dictionary (optional). + :param source_path: The location of the source of this content (if any). + :param context: The shared context between generators. + """ - mandatory_properties = ('title',) - default_template = 'page' + @deprecated_attribute(old='filename', new='source_path', since=(3, 2, 0)) + def filename(): + return None def __init__(self, content, metadata=None, settings=None, - filename=None): - # init parameters - if not metadata: + source_path=None, context=None): + if metadata is None: metadata = {} - if not settings: - settings = copy.deepcopy(_DEFAULT_CONFIG) + if settings is None: + settings = copy.deepcopy(DEFAULT_CONFIG) self.settings = settings self._content = content + if context is None: + context = {} + self._context = context self.translations = [] - local_metadata = dict(settings.get('DEFAULT_METADATA', ())) + local_metadata = dict(settings['DEFAULT_METADATA']) local_metadata.update(metadata) # set metadata as attributes for key, value in local_metadata.items(): + if key in ('save_as', 'url'): + key = 'override_' + key setattr(self, key.lower(), value) # also keep track of the metadata attributes available @@ -49,15 +67,18 @@ class Page(object): #default template if it's not defined in page self.template = self._get_template() - # default author to the one in settings if not defined + # First, read the authors from "authors", if not, fallback to "author" + # and if not use the settings defined one, if any. if not hasattr(self, 'author'): - if 'AUTHOR' in settings: + if hasattr(self, 'authors'): + self.author = self.authors[0] + elif 'AUTHOR' in settings: self.author = Author(settings['AUTHOR'], settings) - else: - title = filename.decode('utf-8') if filename else self.title - self.author = Author(getenv('USER', 'John Doe'), settings) - logger.warning(u"Author of `{0}' unknown, assuming that his name is " - "`{1}'".format(title, self.author)) + + if not hasattr(self, 'authors') and hasattr(self, 'author'): + self.authors = [self.author] + + # XXX Split all the following code into pieces, there is too much here. # manage languages self.in_default_lang = True @@ -68,12 +89,18 @@ class Page(object): self.in_default_lang = (self.lang == default_lang) - # create the slug if not existing, from the title - if not hasattr(self, 'slug') and hasattr(self, 'title'): - self.slug = slugify(self.title) + # create the slug if not existing, generate slug according to + # setting of SLUG_ATTRIBUTE + if not hasattr(self, 'slug'): + if settings['SLUGIFY_SOURCE'] == 'title' and hasattr(self, 'title'): + self.slug = slugify(self.title, + settings.get('SLUG_SUBSTITUTIONS', ())) + elif settings['SLUGIFY_SOURCE'] == 'basename' and source_path != None: + basename = os.path.basename(os.path.splitext(source_path)[0]) + self.slug = slugify(basename, + settings.get('SLUG_SUBSTITUTIONS', ())) - if filename: - self.filename = filename + self.source_path = source_path # manage the date format if not hasattr(self, 'date_format'): @@ -83,80 +110,207 @@ class Page(object): self.date_format = settings['DEFAULT_DATE_FORMAT'] if isinstance(self.date_format, tuple): - locale.setlocale(locale.LC_ALL, self.date_format[0]) + locale_string = self.date_format[0] + if sys.version_info < (3, ) and isinstance(locale_string, + six.text_type): + locale_string = locale_string.encode('ascii') + locale.setlocale(locale.LC_ALL, locale_string) self.date_format = self.date_format[1] - if hasattr(self, 'date'): - encoded_date = self.date.strftime( - self.date_format.encode('ascii', 'xmlcharrefreplace')) + # manage timezone + default_timezone = settings.get('TIMEZONE', 'UTC') + timezone = getattr(self, 'timezone', default_timezone) - if platform == 'win32': - self.locale_date = encoded_date.decode(stdin.encoding) - else: - self.locale_date = encoded_date.decode('utf') + if hasattr(self, 'date'): + self.date = set_date_tzinfo(self.date, timezone) + self.locale_date = strftime(self.date, self.date_format) + + if hasattr(self, 'modified'): + self.modified = set_date_tzinfo(self.modified, timezone) + self.locale_modified = strftime(self.modified, self.date_format) # manage status if not hasattr(self, 'status'): self.status = settings['DEFAULT_STATUS'] if not settings['WITH_FUTURE_DATES']: - if hasattr(self, 'date') and self.date > datetime.now(): + if hasattr(self, 'date') and self.date > SafeDatetime.now(): self.status = 'draft' # store the summary metadata if it is set if 'summary' in metadata: self._summary = metadata['summary'] - signals.content_object_init.send(self.__class__, instance=self) + signals.content_object_init.send(self) + + def __str__(self): + if self.source_path is None: + return repr(self) + elif six.PY3: + return self.source_path or repr(self) + else: + return str(self.source_path.encode('utf-8', 'replace')) def check_properties(self): - """test that each mandatory property is set.""" + """Test mandatory properties are set.""" for prop in self.mandatory_properties: if not hasattr(self, prop): raise NameError(prop) @property def url_format(self): - return { + """Returns the URL, formatted with the proper values""" + metadata = copy.copy(self.metadata) + path = self.metadata.get('path', self.get_relative_source_path()) + default_category = self.settings['DEFAULT_CATEGORY'] + slug_substitutions = self.settings.get('SLUG_SUBSTITUTIONS', ()) + metadata.update({ + 'path': path_to_url(path), 'slug': getattr(self, 'slug', ''), 'lang': getattr(self, 'lang', 'en'), - 'date': getattr(self, 'date', datetime.now()), - 'author': self.author, - 'category': getattr(self, 'category', 'misc'), - } + 'date': getattr(self, 'date', SafeDatetime.now()), + 'author': slugify( + getattr(self, 'author', ''), + slug_substitutions + ), + 'category': slugify( + getattr(self, 'category', default_category), + slug_substitutions + ) + }) + return metadata def _expand_settings(self, key): fq_key = ('%s_%s' % (self.__class__.__name__, key)).upper() return self.settings[fq_key].format(**self.url_format) def get_url_setting(self, key): + if hasattr(self, 'override_' + key): + return getattr(self, 'override_' + key) key = key if self.in_default_lang else 'lang_%s' % key return self._expand_settings(key) - @property - def content(self): - if hasattr(self, "_get_content"): + def _update_content(self, content, siteurl): + """Update the content attribute. + + Change all the relative paths of the content to relative paths + suitable for the output content. + + :param content: content resource that will be passed to the templates. + :param siteurl: siteurl which is locally generated by the writer in + case of RELATIVE_URLS. + """ + if not content: + return content + + instrasite_link_regex = self.settings['INTRASITE_LINK_REGEX'] + regex = r""" + (?P<\s*[^\>]* # match tag with all url-value attributes + (?:href|src|poster|data|cite|formaction|action)\s*=) + + (?P["\']) # require value to be quoted + (?P{0}(?P.*?)) # the url value + \2""".format(instrasite_link_regex) + hrefs = re.compile(regex, re.X) + + def replacer(m): + what = m.group('what') + value = urlparse(m.group('value')) + path = value.path + origin = m.group('path') + + # XXX Put this in a different location. + if what in {'filename', 'attach'}: + if path.startswith('/'): + path = path[1:] + else: + # relative to the source path of this content + path = self.get_relative_source_path( + os.path.join(self.relative_dir, path) + ) + + if path not in self._context['filenames']: + unquoted_path = path.replace('%20', ' ') + + if unquoted_path in self._context['filenames']: + path = unquoted_path + + linked_content = self._context['filenames'].get(path) + if linked_content: + if what == 'attach': + if isinstance(linked_content, Static): + linked_content.attach_to(self) + else: + logger.warning("%s used {attach} link syntax on a " + "non-static file. Use {filename} instead.", + self.get_relative_source_path()) + origin = '/'.join((siteurl, linked_content.url)) + origin = origin.replace('\\', '/') # for Windows paths. + else: + logger.warning( + "Unable to find `%s`, skipping url replacement.", + value.geturl(), extra = { + 'limit_msg': ("Other resources were not found " + "and their urls not replaced")}) + elif what == 'category': + origin = Category(path, self.settings).url + elif what == 'tag': + origin = Tag(path, self.settings).url + + # keep all other parts, such as query, fragment, etc. + parts = list(value) + parts[2] = origin + origin = urlunparse(parts) + + return ''.join((m.group('markup'), m.group('quote'), origin, + m.group('quote'))) + + return hrefs.sub(replacer, content) + + @memoized + def get_content(self, siteurl): + if hasattr(self, '_get_content'): content = self._get_content() else: content = self._content - return content + return self._update_content(content, siteurl) + + def get_siteurl(self): + return self._context.get('localsiteurl', '') + + @property + def content(self): + return self.get_content(self.get_siteurl()) def _get_summary(self): - """Returns the summary of an article, based on the summary metadata - if it is set, else truncate the content.""" + """Returns the summary of an article. + + This is based on the summary metadata if set, otherwise truncate the + content. + """ if hasattr(self, '_summary'): - return self._summary - else: - if self.settings['SUMMARY_MAX_LENGTH']: - return truncate_html_words(self.content, self.settings['SUMMARY_MAX_LENGTH']) + return self._update_content(self._summary, + self.get_siteurl()) + + if self.settings['SUMMARY_MAX_LENGTH'] is None: return self.content - def _set_summary(self, summary): + return truncate_html_words(self.content, + self.settings['SUMMARY_MAX_LENGTH']) + + @memoized + def get_summary(self, siteurl): + """uses siteurl to be memoizable""" + return self._get_summary() + + @property + def summary(self): + return self.get_summary(self.get_siteurl()) + + @summary.setter + def summary(self, value): """Dummy function""" pass - summary = property(_get_summary, _set_summary, "Summary of the article." - "Based on the content. Can't be set") - url = property(functools.partial(get_url_setting, key='url')) save_as = property(functools.partial(get_url_setting, key='save_as')) @@ -166,68 +320,132 @@ class Page(object): else: return self.default_template + def get_relative_source_path(self, source_path=None): + """Return the relative path (from the content path) to the given + source_path. + + If no source path is specified, use the source path of this + content object. + """ + if not source_path: + source_path = self.source_path + if source_path is None: + return None + + return os.path.relpath( + os.path.abspath(os.path.join(self.settings['PATH'], source_path)), + os.path.abspath(self.settings['PATH']) + ) + + @property + def relative_dir(self): + return os.path.dirname(os.path.relpath( + os.path.abspath(self.source_path), + os.path.abspath(self.settings['PATH'])) + ) + + +class Page(Content): + mandatory_properties = ('title',) + default_template = 'page' + class Article(Page): mandatory_properties = ('title', 'date', 'category') default_template = 'article' +class Draft(Page): + mandatory_properties = ('title', 'category') + default_template = 'article' + + class Quote(Page): base_properties = ('author', 'date') -class URLWrapper(object): - def __init__(self, name, settings): - self.name = unicode(name) - self.slug = slugify(self.name) - self.settings = settings +@python_2_unicode_compatible +class Static(Page): + def __init__(self, *args, **kwargs): + super(Static, self).__init__(*args, **kwargs) + self._output_location_referenced = False - def as_dict(self): - return self.__dict__ + @deprecated_attribute(old='filepath', new='source_path', since=(3, 2, 0)) + def filepath(): + return None - def __hash__(self): - return hash(self.name) + @deprecated_attribute(old='src', new='source_path', since=(3, 2, 0)) + def src(): + return None - def __eq__(self, other): - return self.name == unicode(other) + @deprecated_attribute(old='dst', new='save_as', since=(3, 2, 0)) + def dst(): + return None - def __str__(self): - return str(self.name.encode('utf-8', 'replace')) + @property + def url(self): + # Note when url has been referenced, so we can avoid overriding it. + self._output_location_referenced = True + return super(Static, self).url - def __unicode__(self): - return self.name + @property + def save_as(self): + # Note when save_as has been referenced, so we can avoid overriding it. + self._output_location_referenced = True + return super(Static, self).save_as - def _from_settings(self, key): - setting = "%s_%s" % (self.__class__.__name__.upper(), key) - value = self.settings[setting] - if not isinstance(value, basestring): - logger.warning(u'%s is set to %s' % (setting, value)) - return value - else: - return unicode(value).format(**self.as_dict()) + def attach_to(self, content): + """Override our output directory with that of the given content object. + """ + # Determine our file's new output path relative to the linking document. + # If it currently lives beneath the linking document's source directory, + # preserve that relationship on output. Otherwise, make it a sibling. + linking_source_dir = os.path.dirname(content.source_path) + tail_path = os.path.relpath(self.source_path, linking_source_dir) + if tail_path.startswith(os.pardir + os.sep): + tail_path = os.path.basename(tail_path) + new_save_as = os.path.join( + os.path.dirname(content.save_as), tail_path) - url = property(functools.partial(_from_settings, key='URL')) - save_as = property(functools.partial(_from_settings, key='SAVE_AS')) + # We do not build our new url by joining tail_path with the linking + # document's url, because we cannot know just by looking at the latter + # whether it points to the document itself or to its parent directory. + # (An url like 'some/content' might mean a directory named 'some' + # with a file named 'content', or it might mean a directory named + # 'some/content' with a file named 'index.html'.) Rather than trying + # to figure it out by comparing the linking document's url and save_as + # path, we simply build our new url from our new save_as path. + new_url = path_to_url(new_save_as) + def _log_reason(reason): + logger.warning("The {attach} link in %s cannot relocate %s " + "because %s. Falling back to {filename} link behavior instead.", + content.get_relative_source_path(), + self.get_relative_source_path(), reason, + extra={'limit_msg': "More {attach} warnings silenced."}) -class Category(URLWrapper): - pass + # We never override an override, because we don't want to interfere + # with user-defined overrides that might be in EXTRA_PATH_METADATA. + if hasattr(self, 'override_save_as') or hasattr(self, 'override_url'): + if new_save_as != self.save_as or new_url != self.url: + _log_reason("its output location was already overridden") + return + # We never change an output path that has already been referenced, + # because we don't want to break links that depend on that path. + if self._output_location_referenced: + if new_save_as != self.save_as or new_url != self.url: + _log_reason("another link already referenced its location") + return -class Tag(URLWrapper): - def __init__(self, name, *args, **kwargs): - super(Tag, self).__init__(unicode.strip(name), *args, **kwargs) - - -class Author(URLWrapper): - pass + self.override_save_as = new_save_as + self.override_url = new_url def is_valid_content(content, f): try: content.check_properties() return True - except NameError, e: - logger.error(u"Skipping %s: impossible to find informations about '%s'"\ - % (f, e)) + except NameError as e: + logger.error("Skipping %s: could not find information about '%s'", f, e) return False diff --git a/pelican/generators.py b/pelican/generators.py index 461c8b46..5122fa6d 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -1,67 +1,84 @@ # -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function + import os +import six import math import random import logging -import datetime -import subprocess +import shutil +import fnmatch +import calendar from codecs import open from collections import defaultdict from functools import partial -from itertools import chain +from itertools import chain, groupby from operator import attrgetter, itemgetter -from jinja2 import Environment, FileSystemLoader, PrefixLoader, ChoiceLoader -from jinja2.exceptions import TemplateNotFound +from jinja2 import (Environment, FileSystemLoader, PrefixLoader, ChoiceLoader, + BaseLoader, TemplateNotFound) -from pelican.contents import Article, Page, Category, is_valid_content -from pelican.readers import read_file -from pelican.utils import copy, process_translations +from pelican.contents import Article, Draft, Page, Static, is_valid_content +from pelican.readers import Readers +from pelican.utils import (copy, process_translations, mkdir_p, DateFormatter, + FileStampDataCacher, python_2_unicode_compatible) from pelican import signals logger = logging.getLogger(__name__) +@python_2_unicode_compatible class Generator(object): """Baseclass generator""" - def __init__(self, *args, **kwargs): - for idx, item in enumerate(('context', 'settings', 'path', 'theme', - 'output_path', 'markup')): - setattr(self, item, args[idx]) + def __init__(self, context, settings, path, theme, output_path, + readers_cache_name='', **kwargs): + self.context = context + self.settings = settings + self.path = path + self.theme = theme + self.output_path = output_path for arg, value in kwargs.items(): setattr(self, arg, value) + self.readers = Readers(self.settings, readers_cache_name) + # templates cache self._templates = {} self._templates_path = [] self._templates_path.append(os.path.expanduser( - os.path.join(self.theme, 'templates'))) - self._templates_path += self.settings.get('EXTRA_TEMPLATES_PATHS', []) - + os.path.join(self.theme, 'templates'))) + self._templates_path += self.settings['EXTRA_TEMPLATES_PATHS'] theme_path = os.path.dirname(os.path.abspath(__file__)) simple_loader = FileSystemLoader(os.path.join(theme_path, "themes", "simple", "templates")) self.env = Environment( + trim_blocks=True, + lstrip_blocks=True, loader=ChoiceLoader([ FileSystemLoader(self._templates_path), simple_loader, # implicit inheritance PrefixLoader({'!simple': simple_loader}) # explicit one ]), - extensions=self.settings.get('JINJA_EXTENSIONS', []), + extensions=self.settings['JINJA_EXTENSIONS'], ) - logger.debug('template list: {0}'.format(self.env.list_templates())) + logger.debug('Template list: %s', self.env.list_templates()) + + # provide utils.strftime as a jinja filter + self.env.filters.update({'strftime': DateFormatter()}) # get custom Jinja filters from user settings - custom_filters = self.settings.get('JINJA_FILTERS', {}) + custom_filters = self.settings['JINJA_FILTERS'] self.env.filters.update(custom_filters) + signals.generator_init.send(self) + def get_template(self, name): """Return the template by name. Use self.theme to get the templates to use, and return a list of @@ -71,34 +88,88 @@ class Generator(object): try: self._templates[name] = self.env.get_template(name + '.html') except TemplateNotFound: - raise Exception('[templates] unable to load %s.html from %s' \ - % (name, self._templates_path)) + raise Exception('[templates] unable to load %s.html from %s' + % (name, self._templates_path)) return self._templates[name] - def get_files(self, path, exclude=[], extensions=None): + def _include_path(self, path, extensions=None): + """Inclusion logic for .get_files(), returns True/False + + :param path: the path which might be including + :param extensions: the list of allowed extensions (if False, all + extensions are allowed) + """ + if extensions is None: + extensions = tuple(self.readers.extensions) + basename = os.path.basename(path) + + #check IGNORE_FILES + ignores = self.settings['IGNORE_FILES'] + if any(fnmatch.fnmatch(basename, ignore) for ignore in ignores): + return False + + if extensions is False or basename.endswith(extensions): + return True + return False + + def get_files(self, paths, exclude=[], extensions=None): """Return a list of files to use, based on rules - :param path: the path to search the file on + :param paths: the list pf paths to search (relative to self.path) :param exclude: the list of path to exclude + :param extensions: the list of allowed extensions (if False, all + extensions are allowed) """ - if not extensions: - extensions = self.markup + if isinstance(paths, six.string_types): + paths = [paths] # backward compatibility for older generators + + # group the exclude dir names by parent path, for use with os.walk() + exclusions_by_dirpath = {} + for e in exclude: + parent_path, subdir = os.path.split(os.path.join(self.path, e)) + exclusions_by_dirpath.setdefault(parent_path, set()).add(subdir) files = [] + for path in paths: + # careful: os.path.join() will add a slash when path == ''. + root = os.path.join(self.path, path) if path else self.path - try: - iter = os.walk(path, followlinks=True) - except TypeError: # python 2.5 does not support followlinks - iter = os.walk(path) - - for root, dirs, temp_files in iter: - for e in exclude: - if e in dirs: - dirs.remove(e) - files.extend([os.sep.join((root, f)) for f in temp_files - if True in [f.endswith(ext) for ext in extensions]]) + if os.path.isdir(root): + for dirpath, dirs, temp_files in os.walk(root, followlinks=True): + for e in exclusions_by_dirpath.get(dirpath, ()): + if e in dirs: + dirs.remove(e) + reldir = os.path.relpath(dirpath, self.path) + for f in temp_files: + fp = os.path.join(reldir, f) + if self._include_path(fp, extensions): + files.append(fp) + elif os.path.exists(root) and self._include_path(path, extensions): + files.append(path) # can't walk non-directories return files + def add_source_path(self, content): + """Record a source file path that a Generator found and processed. + Store a reference to its Content object, for url lookups later. + """ + location = content.get_relative_source_path() + self.context['filenames'][location] = content + + def _add_failed_source_path(self, path): + """Record a source file path that a Generator failed to process. + (For example, one that was missing mandatory metadata.) + The path argument is expected to be relative to self.path. + """ + self.context['filenames'][os.path.normpath(path)] = None + + def _is_potential_source_path(self, path): + """Return True if path was supposed to be used as a source file. + (This includes all source files that have been found by generators + before this method is called, even if they failed to process.) + The path argument is expected to be relative to self.path. + """ + return os.path.normpath(path) in self.context['filenames'] + def _update_context(self, items): """Update the context with the given items from the currrent processor. @@ -106,11 +177,74 @@ class Generator(object): for item in items: value = getattr(self, item) if hasattr(value, 'items'): - value = value.items() + value = list(value.items()) # py3k safeguard for iterators self.context[item] = value + def __str__(self): + # return the name of the class for logging purposes + return self.__class__.__name__ -class ArticlesGenerator(Generator): + +class CachingGenerator(Generator, FileStampDataCacher): + '''Subclass of Generator and FileStampDataCacher classes + + enables content caching, either at the generator or reader level + ''' + + def __init__(self, *args, **kwargs): + '''Initialize the generator, then set up caching + + note the multiple inheritance structure + ''' + cls_name = self.__class__.__name__ + Generator.__init__(self, *args, + readers_cache_name=(cls_name + '-Readers'), + **kwargs) + + cache_this_level = self.settings['CONTENT_CACHING_LAYER'] == 'generator' + caching_policy = cache_this_level and self.settings['CACHE_CONTENT'] + load_policy = cache_this_level and self.settings['LOAD_CONTENT_CACHE'] + FileStampDataCacher.__init__(self, self.settings, cls_name, + caching_policy, load_policy + ) + + def _get_file_stamp(self, filename): + '''Get filestamp for path relative to generator.path''' + filename = os.path.join(self.path, filename) + return super(CachingGenerator, self)._get_file_stamp(filename) + + +class _FileLoader(BaseLoader): + + def __init__(self, path, basedir): + self.path = path + self.fullpath = os.path.join(basedir, path) + + def get_source(self, environment, template): + if template != self.path or not os.path.exists(self.fullpath): + raise TemplateNotFound(template) + mtime = os.path.getmtime(self.fullpath) + with open(self.fullpath, 'r', encoding='utf-8') as f: + source = f.read() + return (source, self.fullpath, + lambda: mtime == os.path.getmtime(self.fullpath)) + + +class TemplatePagesGenerator(Generator): + + def generate_output(self, writer): + for source, dest in self.settings['TEMPLATE_PAGES'].items(): + self.env.loader.loaders.insert(0, _FileLoader(source, self.path)) + try: + template = self.env.get_template(source) + rurls = self.settings['RELATIVE_URLS'] + writer.write_file(dest, template, self.context, rurls, + override_output=True) + finally: + del self.env.loader.loaders[0] + + +class ArticlesGenerator(CachingGenerator): """Generate blog articles""" def __init__(self, *args, **kwargs): @@ -122,18 +256,13 @@ class ArticlesGenerator(Generator): self.categories = defaultdict(list) self.related_posts = [] self.authors = defaultdict(list) + self.drafts = [] # only drafts in default language + self.drafts_translations = [] super(ArticlesGenerator, self).__init__(*args, **kwargs) - self.drafts = [] signals.article_generator_init.send(self) def generate_feeds(self, writer): """Generate the feeds from the current context, and output files.""" - if self.settings.get('FEED_ATOM') is None and self.settings.get('FEED_RSS') is None: - return - elif self.settings.get('SITEURL') is '': - logger.warning( - 'Feeds generated without SITEURL set properly may not be valid' - ) if self.settings.get('FEED_ATOM'): writer.write_feed(self.articles, self.context, @@ -143,60 +272,157 @@ class ArticlesGenerator(Generator): writer.write_feed(self.articles, self.context, self.settings['FEED_RSS'], feed_type='rss') + if (self.settings.get('FEED_ALL_ATOM') + or self.settings.get('FEED_ALL_RSS')): + all_articles = list(self.articles) + for article in self.articles: + all_articles.extend(article.translations) + all_articles.sort(key=attrgetter('date'), reverse=True) + + if self.settings.get('FEED_ALL_ATOM'): + writer.write_feed(all_articles, self.context, + self.settings['FEED_ALL_ATOM']) + + if self.settings.get('FEED_ALL_RSS'): + writer.write_feed(all_articles, self.context, + self.settings['FEED_ALL_RSS'], + feed_type='rss') + for cat, arts in self.categories: arts.sort(key=attrgetter('date'), reverse=True) if self.settings.get('CATEGORY_FEED_ATOM'): writer.write_feed(arts, self.context, - self.settings['CATEGORY_FEED_ATOM'] % cat) + self.settings['CATEGORY_FEED_ATOM'] + % cat.slug) if self.settings.get('CATEGORY_FEED_RSS'): writer.write_feed(arts, self.context, - self.settings['CATEGORY_FEED_RSS'] % cat, - feed_type='rss') + self.settings['CATEGORY_FEED_RSS'] + % cat.slug, feed_type='rss') - if self.settings.get('TAG_FEED_ATOM') or self.settings.get('TAG_FEED_RSS'): + for auth, arts in self.authors: + arts.sort(key=attrgetter('date'), reverse=True) + if self.settings.get('AUTHOR_FEED_ATOM'): + writer.write_feed(arts, self.context, + self.settings['AUTHOR_FEED_ATOM'] + % auth.slug) + + if self.settings.get('AUTHOR_FEED_RSS'): + writer.write_feed(arts, self.context, + self.settings['AUTHOR_FEED_RSS'] + % auth.slug, feed_type='rss') + + if (self.settings.get('TAG_FEED_ATOM') + or self.settings.get('TAG_FEED_RSS')): for tag, arts in self.tags.items(): arts.sort(key=attrgetter('date'), reverse=True) if self.settings.get('TAG_FEED_ATOM'): writer.write_feed(arts, self.context, - self.settings['TAG_FEED_ATOM'] % tag) + self.settings['TAG_FEED_ATOM'] + % tag.slug) if self.settings.get('TAG_FEED_RSS'): writer.write_feed(arts, self.context, - self.settings['TAG_FEED_RSS'] % tag, + self.settings['TAG_FEED_RSS'] % tag.slug, feed_type='rss') - if self.settings.get('TRANSLATION_FEED'): + if (self.settings.get('TRANSLATION_FEED_ATOM') + or self.settings.get('TRANSLATION_FEED_RSS')): translations_feeds = defaultdict(list) for article in chain(self.articles, self.translations): translations_feeds[article.lang].append(article) for lang, items in translations_feeds.items(): items.sort(key=attrgetter('date'), reverse=True) - writer.write_feed(items, self.context, - self.settings['TRANSLATION_FEED'] % lang) + if self.settings.get('TRANSLATION_FEED_ATOM'): + writer.write_feed( + items, self.context, + self.settings['TRANSLATION_FEED_ATOM'] % lang) + if self.settings.get('TRANSLATION_FEED_RSS'): + writer.write_feed( + items, self.context, + self.settings['TRANSLATION_FEED_RSS'] % lang, + feed_type='rss') def generate_articles(self, write): """Generate the articles.""" for article in chain(self.translations, self.articles): + signals.article_generator_write_article.send(self, content=article) write(article.save_as, self.get_template(article.template), - self.context, article=article, category=article.category) + self.context, article=article, category=article.category, + override_output=hasattr(article, 'override_save_as')) + + def generate_period_archives(self, write): + """Generate per-year, per-month, and per-day archives.""" + try: + template = self.get_template('period_archives') + except Exception: + template = self.get_template('archives') + + period_save_as = { + 'year': self.settings['YEAR_ARCHIVE_SAVE_AS'], + 'month': self.settings['MONTH_ARCHIVE_SAVE_AS'], + 'day': self.settings['DAY_ARCHIVE_SAVE_AS'], + } + + period_date_key = { + 'year': attrgetter('date.year'), + 'month': attrgetter('date.year', 'date.month'), + 'day': attrgetter('date.year', 'date.month', 'date.day') + } + + def _generate_period_archives(dates, key, save_as_fmt): + """Generate period archives from `dates`, grouped by + `key` and written to `save_as`. + """ + # `dates` is already sorted by date + for _period, group in groupby(dates, key=key): + archive = list(group) + # arbitrarily grab the first date so that the usual + # format string syntax can be used for specifying the + # period archive dates + date = archive[0].date + save_as = save_as_fmt.format(date=date) + context = self.context.copy() + + if key == period_date_key['year']: + context["period"] = (_period,) + else: + month_name = calendar.month_name[_period[1]] + if not six.PY3: + month_name = month_name.decode('utf-8') + if key == period_date_key['month']: + context["period"] = (_period[0], + month_name) + else: + context["period"] = (_period[0], + month_name, + _period[2]) + + write(save_as, template, context, + dates=archive, blog=True) + + for period in 'year', 'month', 'day': + save_as = period_save_as[period] + if save_as: + key = period_date_key[period] + _generate_period_archives(self.dates, key, save_as) def generate_direct_templates(self, write): """Generate direct templates pages""" - PAGINATED_TEMPLATES = self.settings.get('PAGINATED_DIRECT_TEMPLATES') - for template in self.settings.get('DIRECT_TEMPLATES'): + PAGINATED_TEMPLATES = self.settings['PAGINATED_DIRECT_TEMPLATES'] + for template in self.settings['DIRECT_TEMPLATES']: paginated = {} if template in PAGINATED_TEMPLATES: paginated = {'articles': self.articles, 'dates': self.dates} save_as = self.settings.get("%s_SAVE_AS" % template.upper(), - '%s.html' % template) + '%s.html' % template) if not save_as: continue write(save_as, self.get_template(template), self.context, blog=True, paginated=paginated, - page_name=template) + page_name=os.path.splitext(save_as)[0]) def generate_tags(self, write): """Generate Tags pages.""" @@ -205,48 +431,51 @@ class ArticlesGenerator(Generator): articles.sort(key=attrgetter('date'), reverse=True) dates = [article for article in self.dates if article in articles] write(tag.save_as, tag_template, self.context, tag=tag, - articles=articles, dates=dates, - paginated={'articles': articles, 'dates': dates}, - page_name=u'tag/%s' % tag) + articles=articles, dates=dates, + paginated={'articles': articles, 'dates': dates}, + page_name=tag.page_name, all_articles=self.articles) def generate_categories(self, write): """Generate category pages.""" category_template = self.get_template('category') for cat, articles in self.categories: + articles.sort(key=attrgetter('date'), reverse=True) dates = [article for article in self.dates if article in articles] write(cat.save_as, category_template, self.context, - category=cat, articles=articles, dates=dates, - paginated={'articles': articles, 'dates': dates}, - page_name=u'category/%s' % cat) + category=cat, articles=articles, dates=dates, + paginated={'articles': articles, 'dates': dates}, + page_name=cat.page_name, all_articles=self.articles) def generate_authors(self, write): """Generate Author pages.""" author_template = self.get_template('author') for aut, articles in self.authors: + articles.sort(key=attrgetter('date'), reverse=True) dates = [article for article in self.dates if article in articles] write(aut.save_as, author_template, self.context, - author=aut, articles=articles, dates=dates, - paginated={'articles': articles, 'dates': dates}, - page_name=u'author/%s' % aut) + author=aut, articles=articles, dates=dates, + paginated={'articles': articles, 'dates': dates}, + page_name=aut.page_name, all_articles=self.articles) def generate_drafts(self, write): """Generate drafts pages.""" - for article in self.drafts: - write('drafts/%s.html' % article.slug, - self.get_template(article.template), self.context, - article=article, category=article.category) + for draft in chain(self.drafts_translations, self.drafts): + write(draft.save_as, self.get_template(draft.template), + self.context, article=draft, category=draft.category, + override_output=hasattr(draft, 'override_save_as'), + all_articles=self.articles) def generate_pages(self, writer): """Generate the pages on the disk""" write = partial(writer.write_file, - relative_urls=self.settings.get('RELATIVE_URLS')) + relative_urls=self.settings['RELATIVE_URLS']) # to minimize the number of relative path stuff modification # in writer, articles pass first self.generate_articles(write) + self.generate_period_archives(write) self.generate_direct_templates(write) - # and subfolders after that self.generate_tags(write) self.generate_categories(write) @@ -254,71 +483,75 @@ class ArticlesGenerator(Generator): self.generate_drafts(write) def generate_context(self): - """change the context""" + """Add the articles into the shared context""" - article_path = os.path.normpath( # we have to remove trailing slashes - os.path.join(self.path, self.settings['ARTICLE_DIR']) - ) all_articles = [] + all_drafts = [] for f in self.get_files( - article_path, + self.settings['ARTICLE_PATHS'], exclude=self.settings['ARTICLE_EXCLUDES']): - try: - content, metadata = read_file(f, settings=self.settings) - except Exception, e: - logger.warning(u'Could not process %s\n%s' % (f, str(e))) - continue + article = self.get_cached_data(f, None) + if article is None: + try: + article = self.readers.read_file( + base_path=self.path, path=f, content_class=Article, + context=self.context, + preread_signal=signals.article_generator_preread, + preread_sender=self, + context_signal=signals.article_generator_context, + context_sender=self) + except Exception as e: + logger.error('Could not process %s\n%s', f, e, + exc_info=self.settings.get('DEBUG', False)) + self._add_failed_source_path(f) + continue - # if no category is set, use the name of the path as a category - if 'category' not in metadata: + if not is_valid_content(article, f): + self._add_failed_source_path(f) + continue - if os.path.dirname(f) == article_path: # if the article is not in a subdirectory - category = self.settings['DEFAULT_CATEGORY'] - else: - category = os.path.basename(os.path.dirname(f))\ - .decode('utf-8') + self.cache_data(f, article) - if category != '': - metadata['category'] = Category(category, self.settings) + self.add_source_path(article) - if 'date' not in metadata and self.settings['DEFAULT_DATE']: - if self.settings['DEFAULT_DATE'] == 'fs': - metadata['date'] = datetime.datetime.fromtimestamp( - os.stat(f).st_ctime) - else: - metadata['date'] = datetime.datetime( - *self.settings['DEFAULT_DATE']) - - signals.article_generate_context.send(self, metadata=metadata) - article = Article(content, metadata, settings=self.settings, - filename=f) - if not is_valid_content(article, f): - continue - - if article.status == "published": - if hasattr(article, 'tags'): - for tag in article.tags: - self.tags[tag].append(article) + if article.status.lower() == "published": all_articles.append(article) - elif article.status == "draft": - self.drafts.append(article) + elif article.status.lower() == "draft": + draft = self.readers.read_file( + base_path=self.path, path=f, content_class=Draft, + context=self.context, + preread_signal=signals.article_generator_preread, + preread_sender=self, + context_signal=signals.article_generator_context, + context_sender=self) + all_drafts.append(draft) else: - logger.warning(u"Unknown status %s for file %s, skipping it." % - (repr(unicode.encode(article.status, 'utf-8')), - repr(f))) + logger.error("Unknown status '%s' for file %s, skipping it.", + article.status, f) - self.articles, self.translations = process_translations(all_articles) + self.articles, self.translations = process_translations(all_articles, + order_by=self.settings['ARTICLE_ORDER_BY']) + self.drafts, self.drafts_translations = \ + process_translations(all_drafts) + + signals.article_generator_pretaxonomy.send(self) for article in self.articles: - # only main articles are listed in categories, not translations + # only main articles are listed in categories and tags + # not translations self.categories[article.category].append(article) - self.authors[article.author].append(article) - + if hasattr(article, 'tags'): + for tag in article.tags: + self.tags[tag].append(article) + # ignore blank authors as well as undefined + for author in getattr(article, 'authors', []): + if author.name != '': + self.authors[author].append(article) # sort the articles by date self.articles.sort(key=attrgetter('date'), reverse=True) self.dates = list(self.articles) self.dates.sort(key=attrgetter('date'), - reverse=self.context['NEWEST_FIRST_ARCHIVES']) + reverse=self.context['NEWEST_FIRST_ARCHIVES']) # create tag cloud tag_cloud = defaultdict(int) @@ -329,7 +562,7 @@ class ArticlesGenerator(Generator): tag_cloud = sorted(tag_cloud.items(), key=itemgetter(1), reverse=True) tag_cloud = tag_cloud[:self.settings.get('TAG_CLOUD_MAX_ITEMS')] - tags = map(itemgetter(1), tag_cloud) + tags = list(map(itemgetter(1), tag_cloud)) if tags: max_count = max(tags) steps = self.settings.get('TAG_CLOUD_STEPS') @@ -351,21 +584,24 @@ class ArticlesGenerator(Generator): # order the categories per name self.categories = list(self.categories.items()) self.categories.sort( - key=lambda item: item[0].name, - reverse=self.settings['REVERSE_CATEGORY_ORDER']) + reverse=self.settings['REVERSE_CATEGORY_ORDER']) self.authors = list(self.authors.items()) - self.authors.sort(key=lambda item: item[0].name) + self.authors.sort() self._update_context(('articles', 'dates', 'tags', 'categories', 'tag_cloud', 'authors', 'related_posts')) + self.save_cache() + self.readers.save_cache() + signals.article_generator_finalized.send(self) def generate_output(self, writer): self.generate_feeds(writer) self.generate_pages(writer) + signals.article_writer_finalized.send(self, writer=writer) -class PagesGenerator(Generator): +class PagesGenerator(CachingGenerator): """Generate pages""" def __init__(self, *args, **kwargs): @@ -373,207 +609,137 @@ class PagesGenerator(Generator): self.hidden_pages = [] self.hidden_translations = [] super(PagesGenerator, self).__init__(*args, **kwargs) - signals.pages_generator_init.send(self) + signals.page_generator_init.send(self) def generate_context(self): all_pages = [] hidden_pages = [] for f in self.get_files( - os.path.join(self.path, self.settings['PAGE_DIR']), + self.settings['PAGE_PATHS'], exclude=self.settings['PAGE_EXCLUDES']): - try: - content, metadata = read_file(f, settings=self.settings) - except Exception, e: - logger.warning(u'Could not process %s\n%s' % (f, str(e))) - continue - signals.pages_generate_context.send(self, metadata=metadata ) - page = Page(content, metadata, settings=self.settings, - filename=f) - if not is_valid_content(page, f): - continue + page = self.get_cached_data(f, None) + if page is None: + try: + page = self.readers.read_file( + base_path=self.path, path=f, content_class=Page, + context=self.context, + preread_signal=signals.page_generator_preread, + preread_sender=self, + context_signal=signals.page_generator_context, + context_sender=self) + except Exception as e: + logger.error('Could not process %s\n%s', f, e, + exc_info=self.settings.get('DEBUG', False)) + self._add_failed_source_path(f) + continue + + if not is_valid_content(page, f): + self._add_failed_source_path(f) + continue + + self.cache_data(f, page) + + self.add_source_path(page) + if page.status == "published": all_pages.append(page) elif page.status == "hidden": hidden_pages.append(page) else: - logger.warning(u"Unknown status %s for file %s, skipping it." % - (repr(unicode.encode(page.status, 'utf-8')), - repr(f))) + logger.error("Unknown status '%s' for file %s, skipping it.", + page.status, f) - self.pages, self.translations = process_translations(all_pages) - self.hidden_pages, self.hidden_translations = process_translations(hidden_pages) + self.pages, self.translations = process_translations(all_pages, + order_by=self.settings['PAGE_ORDER_BY']) + self.hidden_pages, self.hidden_translations = ( + process_translations(hidden_pages)) self._update_context(('pages', )) self.context['PAGES'] = self.pages + self.save_cache() + self.readers.save_cache() + signals.page_generator_finalized.send(self) + def generate_output(self, writer): for page in chain(self.translations, self.pages, - self.hidden_translations, self.hidden_pages): - writer.write_file(page.save_as, self.get_template(page.template), - self.context, page=page, - relative_urls=self.settings.get('RELATIVE_URLS')) + self.hidden_translations, self.hidden_pages): + writer.write_file( + page.save_as, self.get_template(page.template), + self.context, page=page, + relative_urls=self.settings['RELATIVE_URLS'], + override_output=hasattr(page, 'override_save_as')) class StaticGenerator(Generator): """copy static paths (what you want to copy, like images, medias etc. to output""" + def __init__(self, *args, **kwargs): + super(StaticGenerator, self).__init__(*args, **kwargs) + signals.static_generator_init.send(self) + def _copy_paths(self, paths, source, destination, output_path, - final_path=None): + final_path=None): """Copy all the paths from source to destination""" for path in paths: - copy(path, source, os.path.join(output_path, destination), - final_path, overwrite=True) + if final_path: + copy(os.path.join(source, path), + os.path.join(output_path, destination, final_path)) + else: + copy(os.path.join(source, path), + os.path.join(output_path, destination, path)) def generate_context(self): + self.staticfiles = [] + for f in self.get_files(self.settings['STATIC_PATHS'], + exclude=self.settings['STATIC_EXCLUDES'], + extensions=False): - if self.settings['WEBASSETS']: - from webassets import Environment as AssetsEnvironment + # skip content source files unless the user explicitly wants them + if self.settings['STATIC_EXCLUDE_SOURCES']: + if self._is_potential_source_path(f): + continue - # Define the assets environment that will be passed to the - # generators. The StaticGenerator must then be run first to have - # the assets in the output_path before generating the templates. - - # Let ASSET_URL honor Pelican's RELATIVE_URLS setting. - # Hint for templates: - # Current version of webassets seem to remove any relative - # paths at the beginning of the URL. So, if RELATIVE_URLS - # is on, ASSET_URL will start with 'theme/', regardless if we - # set assets_url here to './theme/' or to 'theme/'. - # XXX However, this breaks the ASSET_URL if user navigates to - # a sub-URL, e.g. if he clicks on a category. To workaround this - # issue, I use - # - # instead of - # - if self.settings.get('RELATIVE_URLS'): - assets_url = './theme/' - else: - assets_url = self.settings['SITEURL'] + '/theme/' - assets_src = os.path.join(self.output_path, 'theme') - self.assets_env = AssetsEnvironment(assets_src, assets_url) - - if logging.getLevelName(logger.getEffectiveLevel()) == "DEBUG": - self.assets_env.debug = True + static = self.readers.read_file( + base_path=self.path, path=f, content_class=Static, + fmt='static', context=self.context, + preread_signal=signals.static_generator_preread, + preread_sender=self, + context_signal=signals.static_generator_context, + context_sender=self) + self.staticfiles.append(static) + self.add_source_path(static) + self._update_context(('staticfiles',)) + signals.static_generator_finalized.send(self) def generate_output(self, writer): - - self._copy_paths(self.settings['STATIC_PATHS'], self.path, - 'static', self.output_path) self._copy_paths(self.settings['THEME_STATIC_PATHS'], self.theme, - 'theme', self.output_path, '.') + self.settings['THEME_STATIC_DIR'], self.output_path, + os.curdir) + # copy all Static files + for sc in self.context['staticfiles']: + source_path = os.path.join(self.path, sc.source_path) + save_as = os.path.join(self.output_path, sc.save_as) + mkdir_p(os.path.dirname(save_as)) + shutil.copy2(source_path, save_as) + logger.info('Copying %s to %s', sc.source_path, sc.save_as) - # copy all the files needed - for source, destination in self.settings['FILES_TO_COPY']: - copy(source, self.path, self.output_path, destination, - overwrite=True) - - -class PdfGenerator(Generator): - """Generate PDFs on the output dir, for all articles and pages coming from - rst""" - def __init__(self, *args, **kwargs): - super(PdfGenerator, self).__init__(*args, **kwargs) - try: - from rst2pdf.createpdf import RstToPdf - pdf_style_path = os.path.join(self.settings['PDF_STYLE_PATH']) \ - if 'PDF_STYLE_PATH' in self.settings.keys() \ - else '' - pdf_style = self.settings['PDF_STYLE'] if 'PDF_STYLE' \ - in self.settings.keys() \ - else 'twelvepoint' - self.pdfcreator = RstToPdf(breakside=0, - stylesheets=[pdf_style], - style_path=[pdf_style_path]) - except ImportError: - raise Exception("unable to find rst2pdf") - - def _create_pdf(self, obj, output_path): - if obj.filename.endswith(".rst"): - filename = obj.slug + ".pdf" - output_pdf = os.path.join(output_path, filename) - # print "Generating pdf for", obj.filename, " in ", output_pdf - with open(obj.filename) as f: - self.pdfcreator.createPdf(text=f.read(), output=output_pdf) - logger.info(u' [ok] writing %s' % output_pdf) - - def generate_context(self): - pass - - def generate_output(self, writer=None): - # we don't use the writer passed as argument here - # since we write our own files - logger.info(u' Generating PDF files...') - pdf_path = os.path.join(self.output_path, 'pdf') - if not os.path.exists(pdf_path): - try: - os.mkdir(pdf_path) - except OSError: - logger.error("Couldn't create the pdf output folder in " + pdf_path) - pass - - for article in self.context['articles']: - self._create_pdf(article, pdf_path) - - for page in self.context['pages']: - self._create_pdf(page, pdf_path) class SourceFileGenerator(Generator): + def generate_context(self): self.output_extension = self.settings['OUTPUT_SOURCES_EXTENSION'] - def _create_source(self, obj, output_path): - filename = os.path.splitext(obj.save_as)[0] - dest = os.path.join(output_path, filename + self.output_extension) - copy('', obj.filename, dest) + def _create_source(self, obj): + output_path, _ = os.path.splitext(obj.save_as) + dest = os.path.join(self.output_path, + output_path + self.output_extension) + copy(obj.source_path, dest) def generate_output(self, writer=None): - logger.info(u' Generating source files...') - for object in chain(self.context['articles'], self.context['pages']): - self._create_source(object, self.output_path) - -class LessCSSGenerator(Generator): - """Compile less css files.""" - - def _compile(self, less_file, source_dir, dest_dir): - base = os.path.relpath(less_file, source_dir) - target = os.path.splitext( - os.path.join(dest_dir, base))[0] + '.css' - target_dir = os.path.dirname(target) - - if not os.path.exists(target_dir): - try: - os.makedirs(target_dir) - except OSError: - logger.error("Couldn't create the less css output folder in " + - target_dir) - - subprocess.call([self._lessc, less_file, target]) - logger.info(u' [ok] compiled %s' % base) - - def generate_output(self, writer=None): - logger.info(u' Compiling less css') - - # store out compiler here, so it won't be evaulted on each run of - # _compile - lg = self.settings['LESS_GENERATOR'] - self._lessc = lg if isinstance(lg, basestring) else 'lessc' - - # walk static paths - for static_path in self.settings['STATIC_PATHS']: - for f in self.get_files( - os.path.join(self.path, static_path), - extensions=['less']): - - self._compile(f, self.path, self.output_path) - - # walk theme static paths - theme_output_path = os.path.join(self.output_path, 'theme') - - for static_path in self.settings['THEME_STATIC_PATHS']: - theme_static_path = os.path.join(self.theme, static_path) - for f in self.get_files( - theme_static_path, - extensions=['less']): - - self._compile(f, theme_static_path, theme_output_path) + logger.info('Generating source files...') + for obj in chain(self.context['articles'], self.context['pages']): + self._create_source(obj) + for obj_trans in obj.translations: + self._create_source(obj_trans) diff --git a/pelican/log.py b/pelican/log.py index 9590d7f6..cd750927 100644 --- a/pelican/log.py +++ b/pelican/log.py @@ -1,3 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function + __all__ = [ 'init' ] @@ -5,66 +8,175 @@ __all__ = [ import os import sys import logging +import locale -from logging import Formatter, getLogger, StreamHandler, DEBUG +from collections import defaultdict, Mapping +import six -RESET_TERM = u'\033[0;m' - -COLOR_CODES = { - 'red': 31, - 'yellow': 33, - 'cyan': 36, - 'white': 37, - 'bgred': 41, - 'bggrey': 100, -} - - -def ansi(color, text): - """Wrap text in an ansi escape sequence""" - code = COLOR_CODES[color] - return u'\033[1;{0}m{1}{2}'.format(code, text, RESET_TERM) - - -class ANSIFormatter(Formatter): - """ - Convert a `logging.LogReport' object into colored text, using ANSI escape sequences. - """ - ## colors: +class BaseFormatter(logging.Formatter): + def __init__(self, fmt=None, datefmt=None): + FORMAT = '%(customlevelname)s %(message)s' + super(BaseFormatter, self).__init__(fmt=FORMAT, datefmt=datefmt) def format(self, record): - if record.levelname is 'INFO': - return ansi('cyan', '-> ') + unicode(record.msg) - elif record.levelname is 'WARNING': - return ansi('yellow', record.levelname) + ': ' + unicode(record.msg) - elif record.levelname is 'ERROR': - return ansi('red', record.levelname) + ': ' + unicode(record.msg) - elif record.levelname is 'CRITICAL': - return ansi('bgred', record.levelname) + ': ' + unicode(record.msg) - elif record.levelname is 'DEBUG': - return ansi('bggrey', record.levelname) + ': ' + unicode(record.msg) + record.__dict__['customlevelname'] = self._get_levelname(record.levelname) + # format multiline messages 'nicely' to make it clear they are together + record.msg = record.msg.replace('\n', '\n | ') + return super(BaseFormatter, self).format(record) + + def formatException(self, ei): + ''' prefix traceback info for better representation ''' + # .formatException returns a bytestring in py2 and unicode in py3 + # since .format will handle unicode conversion, + # str() calls are used to normalize formatting string + s = super(BaseFormatter, self).formatException(ei) + # fancy format traceback + s = str('\n').join(str(' | ') + line for line in s.splitlines()) + # separate the traceback from the preceding lines + s = str(' |___\n{}').format(s) + return s + + def _get_levelname(self, name): + ''' NOOP: overridden by subclasses ''' + return name + + +class ANSIFormatter(BaseFormatter): + ANSI_CODES = { + 'red': '\033[1;31m', + 'yellow': '\033[1;33m', + 'cyan': '\033[1;36m', + 'white': '\033[1;37m', + 'bgred': '\033[1;41m', + 'bggrey': '\033[1;100m', + 'reset': '\033[0;m'} + + LEVEL_COLORS = { + 'INFO': 'cyan', + 'WARNING': 'yellow', + 'ERROR': 'red', + 'CRITICAL': 'bgred', + 'DEBUG': 'bggrey'} + + def _get_levelname(self, name): + color = self.ANSI_CODES[self.LEVEL_COLORS.get(name, 'white')] + if name == 'INFO': + fmt = '{0}->{2}' else: - return ansi('white', record.levelname) + ': ' + unicode(record.msg) + fmt = '{0}{1}{2}:' + return fmt.format(color, name, self.ANSI_CODES['reset']) -class TextFormatter(Formatter): +class TextFormatter(BaseFormatter): """ - Convert a `logging.LogReport' object into text. + Convert a `logging.LogRecord' object into text. """ - def format(self, record): - if not record.levelname or record.levelname is 'INFO': - return record.msg + def _get_levelname(self, name): + if name == 'INFO': + return '->' else: - return record.levelname + ': ' + record.msg + return name + ':' -def init(level=None, logger=getLogger(), handler=StreamHandler()): +class LimitFilter(logging.Filter): + """ + Remove duplicates records, and limit the number of records in the same + group. + + Groups are specified by the message to use when the number of records in + the same group hit the limit. + E.g.: log.warning(('43 is not the answer', 'More erroneous answers')) + """ + + _ignore = set() + _threshold = 5 + _group_count = defaultdict(int) + + def filter(self, record): + # don't limit log messages for anything above "warning" + if record.levelno > logging.WARN: + return True + + # extract group + group = record.__dict__.get('limit_msg', None) + group_args = record.__dict__.get('limit_args', ()) + + # ignore record if it was already raised + # use .getMessage() and not .msg for string formatting + ignore_key = (record.levelno, record.getMessage()) + if ignore_key in self._ignore: + return False + else: + self._ignore.add(ignore_key) + + # check if we went over threshold + if group: + key = (record.levelno, group) + self._group_count[key] += 1 + if self._group_count[key] == self._threshold: + record.msg = group + record.args = group_args + elif self._group_count[key] > self._threshold: + return False + return True + + +class SafeLogger(logging.Logger): + """ + Base Logger which properly encodes Exceptions in Py2 + """ + _exc_encoding = locale.getpreferredencoding() + + def _log(self, level, msg, args, exc_info=None, extra=None): + # if the only argument is a Mapping, Logger uses that for formatting + # format values for that case + if args and len(args)==1 and isinstance(args[0], Mapping): + args = ({k: self._decode_arg(v) for k, v in args[0].items()},) + # otherwise, format each arg + else: + args = tuple(self._decode_arg(arg) for arg in args) + super(SafeLogger, self)._log(level, msg, args, + exc_info=exc_info, extra=extra) + + def _decode_arg(self, arg): + ''' + properly decode an arg for Py2 if it's Exception + + + localized systems have errors in native language if locale is set + so convert the message to unicode with the correct encoding + ''' + if isinstance(arg, Exception): + text = str(arg) + if six.PY2: + text = text.decode(self._exc_encoding) + return text + else: + return arg + + +class LimitLogger(SafeLogger): + """ + A logger which adds LimitFilter automatically + """ + + limit_filter = LimitFilter() + + def __init__(self, *args, **kwargs): + super(LimitLogger, self).__init__(*args, **kwargs) + self.addFilter(LimitLogger.limit_filter) + +logging.setLoggerClass(LimitLogger) + + +def init(level=None, handler=logging.StreamHandler()): + logger = logging.getLogger() - if os.isatty(sys.stdout.fileno()) \ - and not sys.platform.startswith('win'): + if (os.isatty(sys.stdout.fileno()) + and not sys.platform.startswith('win')): fmt = ANSIFormatter() else: fmt = TextFormatter() @@ -76,7 +188,7 @@ def init(level=None, logger=getLogger(), handler=StreamHandler()): if __name__ == '__main__': - init(level=DEBUG) + init(level=logging.DEBUG) root_logger = logging.getLogger() root_logger.debug('debug') diff --git a/pelican/paginator.py b/pelican/paginator.py index fe871491..3f5cce47 100644 --- a/pelican/paginator.py +++ b/pelican/paginator.py @@ -1,12 +1,37 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function +import six + # From django.core.paginator +from collections import namedtuple +import functools +import logging +import os + from math import ceil +logger = logging.getLogger(__name__) + + +PaginationRule = namedtuple( + 'PaginationRule', + 'min_page URL SAVE_AS', +) + class Paginator(object): - def __init__(self, object_list, per_page, orphans=0): + def __init__(self, name, object_list, settings): + self.name = name self.object_list = object_list - self.per_page = per_page - self.orphans = orphans + self.settings = settings + + if settings.get('DEFAULT_PAGINATION'): + self.per_page = settings.get('DEFAULT_PAGINATION') + self.orphans = settings.get('DEFAULT_ORPHANS') + else: + self.per_page = len(object_list) + self.orphans = 0 + self._num_pages = self._count = None def page(self, number): @@ -15,7 +40,8 @@ class Paginator(object): top = bottom + self.per_page if top + self.orphans >= self.count: top = self.count - return Page(self.object_list[bottom:top], number, self) + return Page(self.name, self.object_list[bottom:top], number, self, + self.settings) def _get_count(self): "Returns the total number of objects, across all pages." @@ -37,15 +63,17 @@ class Paginator(object): Returns a 1-based range of pages for iterating through within a template for loop. """ - return range(1, self.num_pages + 1) + return list(range(1, self.num_pages + 1)) page_range = property(_get_page_range) class Page(object): - def __init__(self, object_list, number, paginator): + def __init__(self, name, object_list, number, paginator, settings): + self.name, self.extension = os.path.splitext(name) self.object_list = object_list self.number = number self.paginator = paginator + self.settings = settings def __repr__(self): return '' % (self.number, self.paginator.num_pages) @@ -84,3 +112,49 @@ class Page(object): if self.number == self.paginator.num_pages: return self.paginator.count return self.number * self.paginator.per_page + + def _from_settings(self, key): + """Returns URL information as defined in settings. Similar to + URLWrapper._from_settings, but specialized to deal with pagination + logic.""" + + rule = None + + # find the last matching pagination rule + for p in self.settings['PAGINATION_PATTERNS']: + if p.min_page <= self.number: + rule = p + + if not rule: + return '' + + prop_value = getattr(rule, key) + + if not isinstance(prop_value, six.string_types): + logger.warning('%s is set to %s', key, prop_value) + return prop_value + + # URL or SAVE_AS is a string, format it with a controlled context + context = { + 'name': self.name, + 'object_list': self.object_list, + 'number': self.number, + 'paginator': self.paginator, + 'settings': self.settings, + 'base_name': os.path.dirname(self.name), + 'number_sep': '/', + 'extension': self.extension, + } + + if self.number == 1: + # no page numbers on the first page + context['number'] = '' + context['number_sep'] = '' + + ret = prop_value.format(**context) + if ret[0] == '/': + ret = ret[1:] + return ret + + url = property(functools.partial(_from_settings, key='URL')) + save_as = property(functools.partial(_from_settings, key='SAVE_AS')) diff --git a/pelican/plugins/github_activity.py b/pelican/plugins/github_activity.py deleted file mode 100644 index f2ba1da7..00000000 --- a/pelican/plugins/github_activity.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- -""" - Copyright (c) Marco Milanesi - - A plugin to list your Github Activity - To enable it set in your pelican config file the GITHUB_ACTIVITY_FEED - parameter pointing to your github activity feed. - - for example my personal activity feed is: - - https://github.com/kpanic.atom - - in your template just write a for in jinja2 syntax against the - github_activity variable. - - i.e. - - - - github_activity is a list containing a list. The first element is the title - and the second element is the raw html from github -""" - -from pelican import signals - - -class GitHubActivity(): - """ - A class created to fetch github activity with feedparser - """ - def __init__(self, generator): - try: - import feedparser - self.activities = feedparser.parse( - generator.settings['GITHUB_ACTIVITY_FEED']) - except ImportError: - raise Exception("Unable to find feedparser") - - def fetch(self): - """ - returns a list of html snippets fetched from github actitivy feed - """ - - entries = [] - for activity in self.activities['entries']: - entries.append( - [element for element in [activity['title'], - activity['content'][0]['value']]]) - - return entries - - -def fetch_github_activity(gen, metadata): - """ - registered handler for the github activity plugin - it puts in generator.context the html needed to be displayed on a - template - """ - - if 'GITHUB_ACTIVITY_FEED' in gen.settings.keys(): - gen.context['github_activity'] = gen.plugin_instance.fetch() - - -def feed_parser_initialization(generator): - """ - Initialization of feed parser - """ - - generator.plugin_instance = GitHubActivity(generator) - - -def register(): - """ - Plugin registration - """ - signals.article_generator_init.connect(feed_parser_initialization) - signals.article_generate_context.connect(fetch_github_activity) diff --git a/pelican/plugins/global_license.py b/pelican/plugins/global_license.py deleted file mode 100644 index 9a0f5206..00000000 --- a/pelican/plugins/global_license.py +++ /dev/null @@ -1,24 +0,0 @@ -from pelican import signals - -""" -License plugin for Pelican -========================== - -This plugin allows you to define a LICENSE setting and adds the contents of that -license variable to the article's context, making that variable available to use -from within your theme's templates. - -Settings: ---------- - -Define LICENSE in your settings file with the contents of your default license. - -""" - -def add_license(generator, metadata): - if 'license' not in metadata.keys()\ - and 'LICENSE' in generator.settings.keys(): - metadata['license'] = generator.settings['LICENSE'] - -def register(): - signals.article_generate_context.connect(add_license) diff --git a/pelican/plugins/gravatar.py b/pelican/plugins/gravatar.py deleted file mode 100644 index a4d11456..00000000 --- a/pelican/plugins/gravatar.py +++ /dev/null @@ -1,42 +0,0 @@ -import hashlib - -from pelican import signals -""" -Gravatar plugin for Pelican -=========================== - -This plugin assigns the ``author_gravatar`` variable to the Gravatar URL and -makes the variable available within the article's context. - -Settings: ---------- - -Add AUTHOR_EMAIL to your settings file to define the default author's email -address. Obviously, that email address must be associated with a Gravatar -account. - -Article metadata: ------------------- - -:email: article's author email - -If one of them are defined, the author_gravatar variable is added to the -article's context. -""" - -def add_gravatar(generator, metadata): - - #first check email - if 'email' not in metadata.keys()\ - and 'AUTHOR_EMAIL' in generator.settings.keys(): - metadata['email'] = generator.settings['AUTHOR_EMAIL'] - - #then add gravatar url - if 'email' in metadata.keys(): - gravatar_url = "http://www.gravatar.com/avatar/" + \ - hashlib.md5(metadata['email'].lower()).hexdigest() - metadata["author_gravatar"] = gravatar_url - - -def register(): - signals.article_generate_context.connect(add_gravatar) diff --git a/pelican/plugins/html_rst_directive.py b/pelican/plugins/html_rst_directive.py deleted file mode 100644 index d0a656f5..00000000 --- a/pelican/plugins/html_rst_directive.py +++ /dev/null @@ -1,63 +0,0 @@ -from docutils import nodes -from docutils.parsers.rst import directives, Directive -from pelican import log - -""" -HTML tags for reStructuredText -============================== - -Directives ----------- - -.. html:: - - (HTML code) - - -Example -------- - -A search engine: - -.. html:: -
      - - - -
      - - -A contact form: - -.. html:: - -
      -

      - -
      - -
      - -

      -
      - -""" - - -class RawHtml(Directive): - required_arguments = 0 - optional_arguments = 0 - final_argument_whitespace = True - has_content = True - - def run(self): - html = u' '.join(self.content) - node = nodes.raw('', html, format='html') - return [node] - - - -def register(): - directives.register_directive('html', RawHtml) - diff --git a/pelican/plugins/initialized.py b/pelican/plugins/initialized.py deleted file mode 100644 index 5e4cf174..00000000 --- a/pelican/plugins/initialized.py +++ /dev/null @@ -1,7 +0,0 @@ -from pelican import signals - -def test(sender): - print "%s initialized !!" % sender - -def register(): - signals.initialized.connect(test) diff --git a/pelican/plugins/related_posts.py b/pelican/plugins/related_posts.py deleted file mode 100644 index 67715023..00000000 --- a/pelican/plugins/related_posts.py +++ /dev/null @@ -1,52 +0,0 @@ -from pelican import signals - -""" -Related posts plugin for Pelican -================================ - -Adds related_posts variable to article's context - -Settings --------- -To enable, add - - from pelican.plugins import related_posts - PLUGINS = [related_posts] - -to your settings.py. - -Usage ------ - {% if article.related_posts %} -
        - {% for related_post in article.related_posts %} -
      • {{ related_post }}
      • - {% endfor %} -
      - {% endif %} - - -""" - -related_posts = [] - - -def add_related_posts(generator, metadata): - if 'tags' in metadata: - for tag in metadata['tags']: - #print tag - for related_article in generator.tags[tag]: - related_posts.append(related_article) - - if len(related_posts) < 1: - return - - relation_score = dict(zip(set(related_posts), map(related_posts.count, - set(related_posts)))) - ranked_related = sorted(relation_score, key=relation_score.get) - - metadata["related_posts"] = ranked_related[:5] - - -def register(): - signals.article_generate_context.connect(add_related_posts) diff --git a/pelican/plugins/sitemap.py b/pelican/plugins/sitemap.py deleted file mode 100644 index ebce1f04..00000000 --- a/pelican/plugins/sitemap.py +++ /dev/null @@ -1,190 +0,0 @@ -import collections -import os.path - -from datetime import datetime -from logging import warning, info -from codecs import open - -from pelican import signals, contents - -TXT_HEADER = u"""{0}/index.html -{0}/archives.html -{0}/tags.html -{0}/categories.html -""" - -XML_HEADER = u""" - -""" - -XML_URL = u""" - -{0}/{1} -{2} -{3} -{4} - -""" - -XML_FOOTER = u""" - -""" - - -def format_date(date): - if date.tzinfo: - tz = date.strftime('%s') - tz = tz[:-2] + ':' + tz[-2:] - else: - tz = "-00:00" - return date.strftime("%Y-%m-%dT%H:%M:%S") + tz - - -class SitemapGenerator(object): - - def __init__(self, context, settings, path, theme, output_path, *null): - - self.output_path = output_path - self.context = context - self.now = datetime.now() - self.siteurl = settings.get('SITEURL') - - self.format = 'xml' - - self.changefreqs = { - 'articles': 'monthly', - 'indexes': 'daily', - 'pages': 'monthly' - } - - self.priorities = { - 'articles': 0.5, - 'indexes': 0.5, - 'pages': 0.5 - } - - config = settings.get('SITEMAP', {}) - - if not isinstance(config, dict): - warning("sitemap plugin: the SITEMAP setting must be a dict") - else: - fmt = config.get('format') - pris = config.get('priorities') - chfreqs = config.get('changefreqs') - - if fmt not in ('xml', 'txt'): - warning("sitemap plugin: SITEMAP['format'] must be `txt' or `xml'") - warning("sitemap plugin: Setting SITEMAP['format'] on `xml'") - elif fmt == 'txt': - self.format = fmt - return - - valid_keys = ('articles', 'indexes', 'pages') - valid_chfreqs = ('always', 'hourly', 'daily', 'weekly', 'monthly', - 'yearly', 'never') - - if isinstance(pris, dict): - for k, v in pris.iteritems(): - if k in valid_keys and not isinstance(v, (int, float)): - default = self.priorities[k] - warning("sitemap plugin: priorities must be numbers") - warning("sitemap plugin: setting SITEMAP['priorities']" - "['{0}'] on {1}".format(k, default)) - pris[k] = default - self.priorities.update(pris) - elif pris is not None: - warning("sitemap plugin: SITEMAP['priorities'] must be a dict") - warning("sitemap plugin: using the default values") - - if isinstance(chfreqs, dict): - for k, v in chfreqs.iteritems(): - if k in valid_keys and v not in valid_chfreqs: - default = self.changefreqs[k] - warning("sitemap plugin: invalid changefreq `{0}'".format(v)) - warning("sitemap plugin: setting SITEMAP['changefreqs']" - "['{0}'] on '{1}'".format(k, default)) - chfreqs[k] = default - self.changefreqs.update(chfreqs) - elif chfreqs is not None: - warning("sitemap plugin: SITEMAP['changefreqs'] must be a dict") - warning("sitemap plugin: using the default values") - - - - def write_url(self, page, fd): - - if getattr(page, 'status', 'published') != 'published': - return - - page_path = os.path.join(self.output_path, page.url) - if not os.path.exists(page_path): - return - - lastmod = format_date(getattr(page, 'date', self.now)) - - if isinstance(page, contents.Article): - pri = self.priorities['articles'] - chfreq = self.changefreqs['articles'] - elif isinstance(page, contents.Page): - pri = self.priorities['pages'] - chfreq = self.changefreqs['pages'] - else: - pri = self.priorities['indexes'] - chfreq = self.changefreqs['indexes'] - - - if self.format == 'xml': - fd.write(XML_URL.format(self.siteurl, page.url, lastmod, chfreq, pri)) - else: - fd.write(self.siteurl + '/' + loc + '\n') - - - def generate_output(self, writer): - path = os.path.join(self.output_path, 'sitemap.{0}'.format(self.format)) - - pages = self.context['pages'] + self.context['articles'] \ - + [ c for (c, a) in self.context['categories']] \ - + [ t for (t, a) in self.context['tags']] \ - + [ a for (a, b) in self.context['authors']] - - for article in self.context['articles']: - pages += article.translations - - info('writing {0}'.format(path)) - - with open(path, 'w', encoding='utf-8') as fd: - - if self.format == 'xml': - fd.write(XML_HEADER) - else: - fd.write(TXT_HEADER.format(self.siteurl)) - - FakePage = collections.namedtuple('FakePage', - ['status', - 'date', - 'url']) - - for standard_page_url in ['index.html', - 'archives.html', - 'tags.html', - 'categories.html']: - fake = FakePage(status='published', - date=self.now, - url=standard_page_url) - self.write_url(fake, fd) - - for page in pages: - self.write_url(page, fd) - - if self.format == 'xml': - fd.write(XML_FOOTER) - - -def get_generators(generators): - return SitemapGenerator - - -def register(): - signals.get_generators.connect(get_generators) diff --git a/pelican/readers.py b/pelican/readers.py index dab829b9..85147e3e 100644 --- a/pelican/readers.py +++ b/pelican/readers.py @@ -1,45 +1,76 @@ # -*- coding: utf-8 -*- -try: - import docutils - import docutils.core - import docutils.io - from docutils.writers.html4css1 import HTMLTranslator +from __future__ import unicode_literals, print_function - # import the directives to have pygments support - from pelican import rstdirectives # NOQA -except ImportError: - core = False +import logging +import os +import re + +import docutils +import docutils.core +import docutils.io +from docutils.writers.html4css1 import HTMLTranslator +import six + +# import the directives to have pygments support +from pelican import rstdirectives # NOQA try: from markdown import Markdown except ImportError: Markdown = False # NOQA -import re +try: + from html import escape +except ImportError: + from cgi import escape +from six.moves.html_parser import HTMLParser -from pelican.contents import Category, Tag, Author -from pelican.utils import get_date, pelican_open +from pelican import signals +from pelican.contents import Page, Category, Tag, Author +from pelican.utils import get_date, pelican_open, FileStampDataCacher, SafeDatetime -_METADATA_PROCESSORS = { - 'tags': lambda x, y: [Tag(tag, y) for tag in unicode(x).split(',')], +METADATA_PROCESSORS = { + 'tags': lambda x, y: [Tag(tag, y) for tag in x.split(',')], 'date': lambda x, y: get_date(x), - 'status': lambda x, y: unicode.strip(x), + 'modified': lambda x, y: get_date(x), + 'status': lambda x, y: x.strip(), 'category': Category, 'author': Author, + 'authors': lambda x, y: [Author(author.strip(), y) for author in x.split(',')], } +logger = logging.getLogger(__name__) -class Reader(object): +class BaseReader(object): + """Base class to read files. + + This class is used to process static files, and it can be inherited for + other types of file. A Reader class must have the following attributes: + + - enabled: (boolean) tell if the Reader class is enabled. It + generally depends on the import of some dependency. + - file_extensions: a list of file extensions that the Reader will process. + - extensions: a list of extensions to use in the reader (typical use is + Markdown). + + """ enabled = True + file_extensions = ['static'] extensions = None def __init__(self, settings): self.settings = settings def process_metadata(self, name, value): - if name in _METADATA_PROCESSORS: - return _METADATA_PROCESSORS[name](value, self.settings) + if name in METADATA_PROCESSORS: + return METADATA_PROCESSORS[name](value, self.settings) return value + def read(self, source_path): + "No-op parser" + content = None + metadata = {} + return content, metadata + class _FieldBodyTranslator(HTMLTranslator): @@ -74,11 +105,35 @@ class PelicanHTMLTranslator(HTMLTranslator): def depart_abbreviation(self, node): self.body.append('') + def visit_image(self, node): + # set an empty alt if alt is not specified + # avoids that alt is taken from src + node['alt'] = node.get('alt', '') + return HTMLTranslator.visit_image(self, node) + + +class RstReader(BaseReader): + """Reader for reStructuredText files""" -class RstReader(Reader): enabled = bool(docutils) file_extensions = ['rst'] + class FileInput(docutils.io.FileInput): + """Patch docutils.io.FileInput to remove "U" mode in py3. + + Universal newlines is enabled by default and "U" mode is deprecated + in py3. + + """ + + def __init__(self, *args, **kwargs): + if six.PY3: + kwargs['mode'] = kwargs.get('mode', 'r').replace('U', '') + docutils.io.FileInput.__init__(self, *args, **kwargs) + + def __init__(self, *args, **kwargs): + super(RstReader, self).__init__(*args, **kwargs) + def _parse_metadata(self, document): """Return the dict containing document metadata""" output = {} @@ -91,6 +146,10 @@ class RstReader(Reader): value = render_node_to_html(document, body_elem) else: value = body_elem.astext() + elif element.tagname == 'authors': # author list + name = element.tagname + value = [element.astext() for element in element.children] + value = ','.join(value) # METADATA_PROCESSORS expects a string else: # standard fields (e.g. address) name = element.tagname value = element.astext() @@ -99,20 +158,29 @@ class RstReader(Reader): output[name] = self.process_metadata(name, value) return output - def _get_publisher(self, filename): - extra_params = {'initial_header_level': '2'} + def _get_publisher(self, source_path): + extra_params = {'initial_header_level': '2', + 'syntax_highlight': 'short', + 'input_encoding': 'utf-8', + 'exit_status_level': 2, + 'embed_stylesheet': False} + user_params = self.settings.get('DOCUTILS_SETTINGS') + if user_params: + extra_params.update(user_params) + pub = docutils.core.Publisher( + source_class=self.FileInput, destination_class=docutils.io.StringOutput) pub.set_components('standalone', 'restructuredtext', 'html') pub.writer.translator_class = PelicanHTMLTranslator pub.process_programmatic_settings(None, extra_params, None) - pub.set_source(source_path=filename) - pub.publish() + pub.set_source(source_path=source_path) + pub.publish(enable_exit_status=True) return pub - def read(self, filename): + def read(self, source_path): """Parses restructured text""" - pub = self._get_publisher(filename) + pub = self._get_publisher(source_path) parts = pub.writer.parts content = parts.get('body') @@ -122,76 +190,402 @@ class RstReader(Reader): return content, metadata -class MarkdownReader(Reader): +class MarkdownReader(BaseReader): + """Reader for Markdown files""" + enabled = bool(Markdown) - file_extensions = ['md', 'markdown', 'mkd'] - extensions = ['codehilite', 'extra'] + file_extensions = ['md', 'markdown', 'mkd', 'mdown'] - def read(self, filename): - """Parse content and metadata of markdown files""" - markdown_extensions = self.settings.get('MARKDOWN_EXTENSIONS', []) - if isinstance(markdown_extensions, (str, unicode)): - markdown_extensions = [m.strip() for m in - markdown_extensions.split(',')] - text = pelican_open(filename) - md = Markdown(extensions=set( - self.extensions + markdown_extensions + ['meta'])) - content = md.convert(text) + def __init__(self, *args, **kwargs): + super(MarkdownReader, self).__init__(*args, **kwargs) + self.extensions = list(self.settings['MD_EXTENSIONS']) + if 'meta' not in self.extensions: + self.extensions.append('meta') + self._source_path = None - metadata = {} - for name, value in md.Meta.items(): + def _parse_metadata(self, meta): + """Return the dict containing document metadata""" + output = {} + for name, value in meta.items(): name = name.lower() - metadata[name] = self.process_metadata(name, value[0]) + if name == "summary": + # handle summary metadata as markdown + # summary metadata is special case and join all list values + summary_values = "\n".join(value) + # reset the markdown instance to clear any state + self._md.reset() + summary = self._md.convert(summary_values) + output[name] = self.process_metadata(name, summary) + elif name in METADATA_PROCESSORS: + if len(value) > 1: + logger.warning('Duplicate definition of `%s` ' + 'for %s. Using first one.', name, self._source_path) + output[name] = self.process_metadata(name, value[0]) + elif len(value) > 1: + # handle list metadata as list of string + output[name] = self.process_metadata(name, value) + else: + # otherwise, handle metadata as single string + output[name] = self.process_metadata(name, value[0]) + return output + + def read(self, source_path): + """Parse content and metadata of markdown files""" + + self._source_path = source_path + self._md = Markdown(extensions=self.extensions) + with pelican_open(source_path) as text: + content = self._md.convert(text) + + metadata = self._parse_metadata(self._md.Meta) return content, metadata -class HtmlReader(Reader): - file_extensions = ['html', 'htm'] - _re = re.compile('\<\!\-\-\#\s?[A-z0-9_-]*\s?\:s?[A-z0-9\s_-]*\s?\-\-\>') +class HTMLReader(BaseReader): + """Parses HTML files as input, looking for meta, title, and body tags""" + + file_extensions = ['htm', 'html'] + enabled = True + + class _HTMLParser(HTMLParser): + def __init__(self, settings, filename): + try: + # Python 3.4+ + HTMLParser.__init__(self, convert_charrefs=False) + except TypeError: + HTMLParser.__init__(self) + self.body = '' + self.metadata = {} + self.settings = settings + + self._data_buffer = '' + + self._filename = filename + + self._in_top_level = True + self._in_head = False + self._in_title = False + self._in_body = False + self._in_tags = False + + def handle_starttag(self, tag, attrs): + if tag == 'head' and self._in_top_level: + self._in_top_level = False + self._in_head = True + elif tag == 'title' and self._in_head: + self._in_title = True + self._data_buffer = '' + elif tag == 'body' and self._in_top_level: + self._in_top_level = False + self._in_body = True + self._data_buffer = '' + elif tag == 'meta' and self._in_head: + self._handle_meta_tag(attrs) + + elif self._in_body: + self._data_buffer += self.build_tag(tag, attrs, False) + + def handle_endtag(self, tag): + if tag == 'head': + if self._in_head: + self._in_head = False + self._in_top_level = True + elif tag == 'title': + self._in_title = False + self.metadata['title'] = self._data_buffer + elif tag == 'body': + self.body = self._data_buffer + self._in_body = False + self._in_top_level = True + elif self._in_body: + self._data_buffer += ''.format(escape(tag)) + + def handle_startendtag(self, tag, attrs): + if tag == 'meta' and self._in_head: + self._handle_meta_tag(attrs) + if self._in_body: + self._data_buffer += self.build_tag(tag, attrs, True) + + def handle_comment(self, data): + self._data_buffer += ''.format(data) + + def handle_data(self, data): + self._data_buffer += data + + def handle_entityref(self, data): + self._data_buffer += '&{};'.format(data) + + def handle_charref(self, data): + self._data_buffer += '&#{};'.format(data) + + def build_tag(self, tag, attrs, close_tag): + result = '<{}'.format(escape(tag)) + for k, v in attrs: + result += ' ' + escape(k) + if v is not None: + result += '="{}"'.format(escape(v)) + if close_tag: + return result + ' />' + return result + '>' + + def _handle_meta_tag(self, attrs): + name = self._attr_value(attrs, 'name') + if name is None: + attr_serialized = ', '.join(['{}="{}"'.format(k, v) for k, v in attrs]) + logger.warning("Meta tag in file %s does not have a 'name' " + "attribute, skipping. Attributes: %s", + self._filename, attr_serialized) + return + name = name.lower() + contents = self._attr_value(attrs, 'content', '') + if not contents: + contents = self._attr_value(attrs, 'contents', '') + if contents: + logger.warning( + "Meta tag attribute 'contents' used in file %s, should" + " be changed to 'content'", + self._filename, + extra={'limit_msg': ("Other files have meta tag " + "attribute 'contents' that should " + "be changed to 'content'")}) + + if name == 'keywords': + name = 'tags' + self.metadata[name] = contents + + @classmethod + def _attr_value(cls, attrs, name, default=None): + return next((x[1] for x in attrs if x[0] == name), default) def read(self, filename): - """Parse content and metadata of (x)HTML files""" + """Parse content and metadata of HTML files""" with pelican_open(filename) as content: - metadata = {'title': 'unnamed'} - for i in self._re.findall(content): - key = i.split(':')[0][5:].strip() - value = i.split(':')[-1][:-3].strip() - name = key.lower() - metadata[name] = self.process_metadata(name, value) + parser = self._HTMLParser(self.settings, filename) + parser.feed(content) + parser.close() - return content, metadata + metadata = {} + for k in parser.metadata: + metadata[k] = self.process_metadata(k, parser.metadata[k]) + return parser.body, metadata -_EXTENSIONS = {} +class Readers(FileStampDataCacher): + """Interface for all readers. -for cls in Reader.__subclasses__(): - for ext in cls.file_extensions: - _EXTENSIONS[ext] = cls + This class contains a mapping of file extensions / Reader classes, to know + which Reader class must be used to read a file (based on its extension). + This is customizable both with the 'READERS' setting, and with the + 'readers_init' signall for plugins. + + """ + + def __init__(self, settings=None, cache_name=''): + self.settings = settings or {} + self.readers = {} + self.reader_classes = {} + + for cls in [BaseReader] + BaseReader.__subclasses__(): + if not cls.enabled: + logger.debug('Missing dependencies for %s', + ', '.join(cls.file_extensions)) + continue + + for ext in cls.file_extensions: + self.reader_classes[ext] = cls + + if self.settings['READERS']: + self.reader_classes.update(self.settings['READERS']) + + signals.readers_init.send(self) + + for fmt, reader_class in self.reader_classes.items(): + if not reader_class: + continue + + self.readers[fmt] = reader_class(self.settings) + + # set up caching + cache_this_level = (cache_name != '' and + self.settings['CONTENT_CACHING_LAYER'] == 'reader') + caching_policy = cache_this_level and self.settings['CACHE_CONTENT'] + load_policy = cache_this_level and self.settings['LOAD_CONTENT_CACHE'] + super(Readers, self).__init__(settings, cache_name, + caching_policy, load_policy, + ) + + @property + def extensions(self): + return self.readers.keys() + + def read_file(self, base_path, path, content_class=Page, fmt=None, + context=None, preread_signal=None, preread_sender=None, + context_signal=None, context_sender=None): + """Return a content object parsed with the given format.""" + + path = os.path.abspath(os.path.join(base_path, path)) + source_path = os.path.relpath(path, base_path) + logger.debug('Read file %s -> %s', + source_path, content_class.__name__) + + if not fmt: + _, ext = os.path.splitext(os.path.basename(path)) + fmt = ext[1:] + + if fmt not in self.readers: + raise TypeError( + 'Pelican does not know how to parse %s', path) + + if preread_signal: + logger.debug('Signal %s.send(%s)', + preread_signal.name, preread_sender) + preread_signal.send(preread_sender) + + reader = self.readers[fmt] + + metadata = default_metadata( + settings=self.settings, process=reader.process_metadata) + metadata.update(path_metadata( + full_path=path, source_path=source_path, + settings=self.settings)) + metadata.update(parse_path_metadata( + source_path=source_path, settings=self.settings, + process=reader.process_metadata)) + reader_name = reader.__class__.__name__ + metadata['reader'] = reader_name.replace('Reader', '').lower() + + content, reader_metadata = self.get_cached_data(path, (None, None)) + if content is None: + content, reader_metadata = reader.read(path) + self.cache_data(path, (content, reader_metadata)) + metadata.update(reader_metadata) + + if content: + # find images with empty alt + find_empty_alt(content, path) + + # eventually filter the content with typogrify if asked so + if self.settings['TYPOGRIFY']: + from typogrify.filters import typogrify + + def typogrify_wrapper(text): + """Ensures ignore_tags feature is backward compatible""" + try: + return typogrify(text, self.settings['TYPOGRIFY_IGNORE_TAGS']) + except TypeError: + return typogrify(text) + + if content: + content = typogrify_wrapper(content) + metadata['title'] = typogrify_wrapper(metadata['title']) + + if 'summary' in metadata: + metadata['summary'] = typogrify_wrapper(metadata['summary']) + + if context_signal: + logger.debug('Signal %s.send(%s, )', + context_signal.name, context_sender) + context_signal.send(context_sender, metadata=metadata) + + return content_class(content=content, metadata=metadata, + settings=self.settings, source_path=path, + context=context) -def read_file(filename, fmt=None, settings=None): - """Return a reader object using the given format.""" - if not fmt: - fmt = filename.split('.')[-1] +def find_empty_alt(content, path): + """Find images with empty alt - if fmt not in _EXTENSIONS: - raise TypeError('Pelican does not know how to parse %s' % filename) + Create warnings for all images with empty alt (up to a certain number), + as they are really likely to be accessibility flaws. - reader = _EXTENSIONS[fmt](settings) - settings_key = '%s_EXTENSIONS' % fmt.upper() + """ + imgs = re.compile(r""" + (?: + # src before alt + ]* + src=(['"])(.*)\1 + [^\>]* + alt=(['"])\3 + )|(?: + # alt before src + ]* + alt=(['"])\4 + [^\>]* + src=(['"])(.*)\5 + ) + """, re.X) + for match in re.findall(imgs, content): + logger.warning( + 'Empty alt attribute for image %s in %s', + os.path.basename(match[1] + match[5]), path, + extra={'limit_msg': 'Other images have empty alt attributes'}) - if settings and settings_key in settings: - reader.extensions = settings[settings_key] - if not reader.enabled: - raise ValueError("Missing dependencies for %s" % fmt) +def default_metadata(settings=None, process=None): + metadata = {} + if settings: + if 'DEFAULT_CATEGORY' in settings: + value = settings['DEFAULT_CATEGORY'] + if process: + value = process('category', value) + metadata['category'] = value + if settings.get('DEFAULT_DATE', None) and settings['DEFAULT_DATE'] != 'fs': + metadata['date'] = SafeDatetime(*settings['DEFAULT_DATE']) + return metadata - content, metadata = reader.read(filename) - # eventually filter the content with typogrify if asked so - if settings and settings['TYPOGRIFY']: - from typogrify.filters import typogrify - content = typogrify(content) - metadata['title'] = typogrify(metadata['title']) +def path_metadata(full_path, source_path, settings=None): + metadata = {} + if settings: + if settings.get('DEFAULT_DATE', None) == 'fs': + metadata['date'] = SafeDatetime.fromtimestamp( + os.stat(full_path).st_ctime) + metadata.update(settings.get('EXTRA_PATH_METADATA', {}).get( + source_path, {})) + return metadata - return content, metadata + +def parse_path_metadata(source_path, settings=None, process=None): + """Extract a metadata dictionary from a file's path + + >>> import pprint + >>> settings = { + ... 'FILENAME_METADATA': '(?P[^.]*).*', + ... 'PATH_METADATA': + ... '(?P[^/]*)/(?P\d{4}-\d{2}-\d{2})/.*', + ... } + >>> reader = BaseReader(settings=settings) + >>> metadata = parse_path_metadata( + ... source_path='my-cat/2013-01-01/my-slug.html', + ... settings=settings, + ... process=reader.process_metadata) + >>> pprint.pprint(metadata) # doctest: +ELLIPSIS + {'category': , + 'date': SafeDatetime(2013, 1, 1, 0, 0), + 'slug': 'my-slug'} + """ + metadata = {} + dirname, basename = os.path.split(source_path) + base, ext = os.path.splitext(basename) + subdir = os.path.basename(dirname) + if settings: + checks = [] + for key, data in [('FILENAME_METADATA', base), + ('PATH_METADATA', source_path)]: + checks.append((settings.get(key, None), data)) + if settings.get('USE_FOLDER_AS_CATEGORY', None): + checks.insert(0, ('(?P.*)', subdir)) + for regexp, data in checks: + if regexp and data: + match = re.match(regexp, data) + if match: + # .items() for py3k compat. + for k, v in match.groupdict().items(): + if k not in metadata: + k = k.lower() # metadata must be lowercase + if process: + v = process(k, v) + metadata[k] = v + return metadata diff --git a/pelican/rstdirectives.py b/pelican/rstdirectives.py index b1f1242c..1bf6971c 100644 --- a/pelican/rstdirectives.py +++ b/pelican/rstdirectives.py @@ -1,25 +1,38 @@ # -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function + from docutils import nodes, utils from docutils.parsers.rst import directives, roles, Directive from pygments.formatters import HtmlFormatter from pygments import highlight from pygments.lexers import get_lexer_by_name, TextLexer import re - -INLINESTYLES = False -DEFAULT = HtmlFormatter(noclasses=INLINESTYLES) -VARIANTS = { - 'linenos': HtmlFormatter(noclasses=INLINESTYLES, linenos=True), -} +import six +import pelican.settings as pys class Pygments(Directive): - """ Source code syntax hightlighting. + """ Source code syntax highlighting. """ required_arguments = 1 optional_arguments = 0 final_argument_whitespace = True - option_spec = dict([(key, directives.flag) for key in VARIANTS]) + option_spec = { + 'anchorlinenos': directives.flag, + 'classprefix': directives.unchanged, + 'hl_lines': directives.unchanged, + 'lineanchors': directives.unchanged, + 'linenos': directives.unchanged, + 'linenospecial': directives.nonnegative_int, + 'linenostart': directives.nonnegative_int, + 'linenostep': directives.nonnegative_int, + 'lineseparator': directives.unchanged, + 'linespans': directives.unchanged, + 'nobackground': directives.flag, + 'nowrap': directives.flag, + 'tagsfile': directives.unchanged, + 'tagurlformat': directives.unchanged, + } has_content = True def run(self): @@ -29,84 +42,48 @@ class Pygments(Directive): except ValueError: # no lexer found - use the text one instead of an exception lexer = TextLexer() - # take an arbitrary option if more than one is given - formatter = self.options and VARIANTS[self.options.keys()[0]] \ - or DEFAULT - parsed = highlight(u'\n'.join(self.content), lexer, formatter) + + # Fetch the defaults + if pys.PYGMENTS_RST_OPTIONS is not None: + for k, v in six.iteritems(pys.PYGMENTS_RST_OPTIONS): + # Locally set options overrides the defaults + if k not in self.options: + self.options[k] = v + + if ('linenos' in self.options and + self.options['linenos'] not in ('table', 'inline')): + if self.options['linenos'] == 'none': + self.options.pop('linenos') + else: + self.options['linenos'] = 'table' + + for flag in ('nowrap', 'nobackground', 'anchorlinenos'): + if flag in self.options: + self.options[flag] = True + + # noclasses should already default to False, but just in case... + formatter = HtmlFormatter(noclasses=False, **self.options) + parsed = highlight('\n'.join(self.content), lexer, formatter) return [nodes.raw('', parsed, format='html')] directives.register_directive('code-block', Pygments) directives.register_directive('sourcecode', Pygments) -class YouTube(Directive): - """ Embed YouTube video in posts. - - Courtesy of Brian Hsu: https://gist.github.com/1422773 - - VIDEO_ID is required, with / height are optional integer, - and align could be left / center / right. - - Usage: - .. youtube:: VIDEO_ID - :width: 640 - :height: 480 - :align: center - """ - - def align(argument): - """Conversion function for the "align" option.""" - return directives.choice(argument, ('left', 'center', 'right')) - - required_arguments = 1 - optional_arguments = 2 - option_spec = { - 'width': directives.positive_int, - 'height': directives.positive_int, - 'align': align - } - - final_argument_whitespace = False - has_content = False - - def run(self): - videoID = self.arguments[0].strip() - width = 420 - height = 315 - align = 'left' - - if 'width' in self.options: - width = self.options['width'] - - if 'height' in self.options: - height = self.options['height'] - - if 'align' in self.options: - align = self.options['align'] - - url = 'http://www.youtube.com/embed/%s' % videoID - div_block = '
      ' % align - embed_block = '' % (width, height, url) - - return [ - nodes.raw('', div_block, format='html'), - nodes.raw('', embed_block, format='html'), - nodes.raw('', '
      ', format='html')] - -directives.register_directive('youtube', YouTube) - _abbr_re = re.compile('\((.*)\)$') -class abbreviation(nodes.Inline, nodes.TextElement): pass + +class abbreviation(nodes.Inline, nodes.TextElement): + pass + def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): - text = utils.unescape(text) - m = _abbr_re.search(text) - if m is None: - return [abbreviation(text, text)], [] - abbr = text[:m.start()].strip() - expl = m.group(1) - return [abbreviation(abbr, abbr, explanation=expl)], [] + text = utils.unescape(text) + m = _abbr_re.search(text) + if m is None: + return [abbreviation(text, text)], [] + abbr = text[:m.start()].strip() + expl = m.group(1) + return [abbreviation(abbr, abbr, explanation=expl)], [] roles.register_local_role('abbr', abbr_role) diff --git a/pelican/server.py b/pelican/server.py new file mode 100644 index 00000000..d4518acd --- /dev/null +++ b/pelican/server.py @@ -0,0 +1,52 @@ +from __future__ import print_function +import os +import sys +import logging +try: + import SimpleHTTPServer as srvmod +except ImportError: + import http.server as srvmod # NOQA + +try: + import SocketServer as socketserver +except ImportError: + import socketserver # NOQA + +PORT = len(sys.argv) == 2 and int(sys.argv[1]) or 8000 +SUFFIXES = ['', '.html', '/index.html'] + + +class ComplexHTTPRequestHandler(srvmod.SimpleHTTPRequestHandler): + def do_GET(self): + # we are trying to detect the file by having a fallback mechanism + found = False + for suffix in SUFFIXES: + if not hasattr(self,'original_path'): + self.original_path = self.path + self.path = self.original_path + suffix + path = self.translate_path(self.path) + if os.path.exists(path): + srvmod.SimpleHTTPRequestHandler.do_GET(self) + logging.info("Found: %s" % self.path) + found = True + break + logging.info("Tried to find file %s, but it doesn't exist. ", self.path) + if not found: + logging.warning("Unable to find file %s or variations.", self.path) + +Handler = ComplexHTTPRequestHandler + +socketserver.TCPServer.allow_reuse_address = True +try: + httpd = socketserver.TCPServer(("", PORT), Handler) +except OSError as e: + logging.error("Could not listen on port %s", PORT) + sys.exit(getattr(e, 'exitcode', 1)) + + +logging.info("Serving at port %s", PORT) +try: + httpd.serve_forever() +except KeyboardInterrupt as e: + logging.info("Shutting down server") + httpd.socket.close() diff --git a/pelican/settings.py b/pelican/settings.py index 7d0f6cdb..794733d7 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -1,188 +1,381 @@ # -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function +import six + import copy -import imp import inspect import os import locale import logging +try: + # SourceFileLoader is the recommended way in 3.3+ + from importlib.machinery import SourceFileLoader + load_source = lambda name, path: SourceFileLoader(name, path).load_module() +except ImportError: + # but it does not exist in 3.2-, so fall back to imp + import imp + load_source = imp.load_source + from os.path import isabs +from pelican.log import LimitFilter + logger = logging.getLogger(__name__) -DEFAULT_THEME = os.sep.join([os.path.dirname(os.path.abspath(__file__)), - "themes/notmyidea"]) -_DEFAULT_CONFIG = {'PATH': '.', - 'ARTICLE_DIR': '', - 'ARTICLE_EXCLUDES': ('pages',), - 'PAGE_DIR': 'pages', - 'PAGE_EXCLUDES': (), - 'THEME': DEFAULT_THEME, - 'OUTPUT_PATH': 'output/', - 'MARKUP': ('rst', 'md'), - 'STATIC_PATHS': ['images', ], - 'THEME_STATIC_PATHS': ['static', ], - 'FEED_ATOM': 'feeds/all.atom.xml', - 'CATEGORY_FEED_ATOM': 'feeds/%s.atom.xml', - 'TRANSLATION_FEED': 'feeds/all-%s.atom.xml', - 'FEED_MAX_ITEMS': '', - 'SITEURL': '', - 'SITENAME': 'A Pelican Blog', - 'DISPLAY_PAGES_ON_MENU': True, - 'PDF_GENERATOR': False, - 'OUTPUT_SOURCES': False, - 'OUTPUT_SOURCES_EXTENSION': '.text', - 'DEFAULT_CATEGORY': 'misc', - 'DEFAULT_DATE': 'fs', - 'WITH_FUTURE_DATES': True, - 'CSS_FILE': 'main.css', - 'NEWEST_FIRST_ARCHIVES': True, - 'REVERSE_CATEGORY_ORDER': False, - 'DELETE_OUTPUT_DIRECTORY': False, - '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', - 'CATEGORY_URL': 'category/{slug}.html', - 'CATEGORY_SAVE_AS': 'category/{slug}.html', - 'TAG_URL': 'tag/{slug}.html', - 'TAG_SAVE_AS': 'tag/{slug}.html', - 'AUTHOR_URL': u'author/{slug}.html', - 'AUTHOR_SAVE_AS': u'author/{slug}.html', - 'RELATIVE_URLS': True, - 'DEFAULT_LANG': 'en', - 'TAG_CLOUD_STEPS': 4, - 'TAG_CLOUD_MAX_ITEMS': 100, - 'DIRECT_TEMPLATES': ('index', 'tags', 'categories', 'archives'), - 'EXTRA_TEMPLATES_PATHS' : [], - 'PAGINATED_DIRECT_TEMPLATES': ('index', ), - 'PELICAN_CLASS': 'pelican.Pelican', - 'DEFAULT_DATE_FORMAT': '%a %d %B %Y', - 'DATE_FORMATS': {}, - 'JINJA_EXTENSIONS': [], - 'LOCALE': '', # default to user locale - 'DEFAULT_PAGINATION': False, - 'DEFAULT_ORPHANS': 0, - 'DEFAULT_METADATA': (), - 'FILES_TO_COPY': (), - 'DEFAULT_STATUS': 'published', - 'ARTICLE_PERMALINK_STRUCTURE': '', - 'TYPOGRIFY': False, - 'LESS_GENERATOR': False, - 'SUMMARY_MAX_LENGTH': 50, - 'WEBASSETS': False, - 'PLUGINS': [], - 'MARKDOWN_EXTENSIONS': ['toc', ], - } +DEFAULT_THEME = os.path.join(os.path.dirname(os.path.abspath(__file__)), + 'themes', 'notmyidea') +DEFAULT_CONFIG = { + 'PATH': os.curdir, + 'ARTICLE_PATHS': [''], + 'ARTICLE_EXCLUDES': [], + 'PAGE_PATHS': ['pages'], + 'PAGE_EXCLUDES': [], + 'THEME': DEFAULT_THEME, + 'OUTPUT_PATH': 'output', + 'READERS': {}, + 'STATIC_PATHS': ['images'], + 'STATIC_EXCLUDES': [], + 'STATIC_EXCLUDE_SOURCES': True, + 'THEME_STATIC_DIR': 'theme', + 'THEME_STATIC_PATHS': ['static', ], + 'FEED_ALL_ATOM': os.path.join('feeds', 'all.atom.xml'), + 'CATEGORY_FEED_ATOM': os.path.join('feeds', '%s.atom.xml'), + 'AUTHOR_FEED_ATOM': os.path.join('feeds', '%s.atom.xml'), + 'AUTHOR_FEED_RSS': os.path.join('feeds', '%s.rss.xml'), + 'TRANSLATION_FEED_ATOM': os.path.join('feeds', 'all-%s.atom.xml'), + 'FEED_MAX_ITEMS': '', + 'SITEURL': '', + 'SITENAME': 'A Pelican Blog', + 'DISPLAY_PAGES_ON_MENU': True, + 'DISPLAY_CATEGORIES_ON_MENU': True, + 'DOCUTILS_SETTINGS': {}, + 'OUTPUT_SOURCES': False, + 'OUTPUT_SOURCES_EXTENSION': '.text', + 'USE_FOLDER_AS_CATEGORY': True, + 'DEFAULT_CATEGORY': 'misc', + 'WITH_FUTURE_DATES': True, + 'CSS_FILE': 'main.css', + 'NEWEST_FIRST_ARCHIVES': True, + 'REVERSE_CATEGORY_ORDER': False, + 'DELETE_OUTPUT_DIRECTORY': False, + 'OUTPUT_RETENTION': (), + 'ARTICLE_URL': '{slug}.html', + 'ARTICLE_SAVE_AS': '{slug}.html', + 'ARTICLE_ORDER_BY': 'slug', + 'ARTICLE_LANG_URL': '{slug}-{lang}.html', + 'ARTICLE_LANG_SAVE_AS': '{slug}-{lang}.html', + 'DRAFT_URL': 'drafts/{slug}.html', + 'DRAFT_SAVE_AS': os.path.join('drafts', '{slug}.html'), + 'DRAFT_LANG_URL': 'drafts/{slug}-{lang}.html', + 'DRAFT_LANG_SAVE_AS': os.path.join('drafts', '{slug}-{lang}.html'), + 'PAGE_URL': 'pages/{slug}.html', + 'PAGE_SAVE_AS': os.path.join('pages', '{slug}.html'), + 'PAGE_ORDER_BY': 'basename', + 'PAGE_LANG_URL': 'pages/{slug}-{lang}.html', + 'PAGE_LANG_SAVE_AS': os.path.join('pages', '{slug}-{lang}.html'), + 'STATIC_URL': '{path}', + 'STATIC_SAVE_AS': '{path}', + 'PDF_GENERATOR': False, + 'PDF_STYLE_PATH': '', + 'PDF_STYLE': 'twelvepoint', + 'CATEGORY_URL': 'category/{slug}.html', + 'CATEGORY_SAVE_AS': os.path.join('category', '{slug}.html'), + 'TAG_URL': 'tag/{slug}.html', + 'TAG_SAVE_AS': os.path.join('tag', '{slug}.html'), + 'AUTHOR_URL': 'author/{slug}.html', + 'AUTHOR_SAVE_AS': os.path.join('author', '{slug}.html'), + 'PAGINATION_PATTERNS': [ + (0, '{name}{number}{extension}', '{name}{number}{extension}'), + ], + 'YEAR_ARCHIVE_SAVE_AS': '', + 'MONTH_ARCHIVE_SAVE_AS': '', + 'DAY_ARCHIVE_SAVE_AS': '', + 'RELATIVE_URLS': False, + 'DEFAULT_LANG': 'en', + 'TAG_CLOUD_STEPS': 4, + 'TAG_CLOUD_MAX_ITEMS': 100, + 'DIRECT_TEMPLATES': ('index', 'tags', 'categories', 'authors', 'archives'), + 'EXTRA_TEMPLATES_PATHS': [], + 'PAGINATED_DIRECT_TEMPLATES': ('index', ), + 'PELICAN_CLASS': 'pelican.Pelican', + 'DEFAULT_DATE_FORMAT': '%a %d %B %Y', + 'DATE_FORMATS': {}, + 'MD_EXTENSIONS': ['codehilite(css_class=highlight)', 'extra'], + 'JINJA_EXTENSIONS': [], + 'JINJA_FILTERS': {}, + 'LOG_FILTER': [], + 'LOCALE': [''], # defaults to user locale + 'DEFAULT_PAGINATION': False, + 'DEFAULT_ORPHANS': 0, + 'DEFAULT_METADATA': (), + 'FILENAME_METADATA': '(?P\d{4}-\d{2}-\d{2}).*', + 'PATH_METADATA': '', + 'EXTRA_PATH_METADATA': {}, + 'DEFAULT_STATUS': 'published', + 'ARTICLE_PERMALINK_STRUCTURE': '', + 'TYPOGRIFY': False, + 'TYPOGRIFY_IGNORE_TAGS': [], + 'SUMMARY_MAX_LENGTH': 50, + 'PLUGIN_PATHS': [], + 'PLUGINS': [], + 'PYGMENTS_RST_OPTIONS': {}, + 'TEMPLATE_PAGES': {}, + 'IGNORE_FILES': ['.#*'], + 'SLUG_SUBSTITUTIONS': (), + 'INTRASITE_LINK_REGEX': '[{|](?P.*?)[|}]', + 'SLUGIFY_SOURCE': 'title', + 'CACHE_CONTENT': True, + 'CONTENT_CACHING_LAYER': 'reader', + 'CACHE_PATH': 'cache', + 'GZIP_CACHE': True, + 'CHECK_MODIFIED_METHOD': 'mtime', + 'LOAD_CONTENT_CACHE': True, + 'AUTORELOAD_IGNORE_CACHE': False, + 'WRITE_SELECTED': [], + } + +PYGMENTS_RST_OPTIONS = None -def read_settings(filename=None): - if filename: - local_settings = get_settings_from_file(filename) +def read_settings(path=None, override=None): + if path: + local_settings = get_settings_from_file(path) + # Make the paths relative to the settings file + for p in ['PATH', 'OUTPUT_PATH', 'THEME', 'CACHE_PATH']: + if p in local_settings and local_settings[p] is not None \ + and not isabs(local_settings[p]): + absp = os.path.abspath(os.path.normpath(os.path.join( + os.path.dirname(path), local_settings[p]))) + if p not in ('THEME') or os.path.exists(absp): + local_settings[p] = absp + + if 'PLUGIN_PATH' in local_settings: + logger.warning('PLUGIN_PATH setting has been replaced by ' + 'PLUGIN_PATHS, moving it to the new setting name.') + local_settings['PLUGIN_PATHS'] = local_settings['PLUGIN_PATH'] + del local_settings['PLUGIN_PATH'] + if isinstance(local_settings['PLUGIN_PATHS'], six.string_types): + logger.warning("Defining PLUGIN_PATHS setting as string " + "has been deprecated (should be a list)") + local_settings['PLUGIN_PATHS'] = [local_settings['PLUGIN_PATHS']] + elif local_settings['PLUGIN_PATHS'] is not None: + local_settings['PLUGIN_PATHS'] = [os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(path), pluginpath))) + if not isabs(pluginpath) else pluginpath for pluginpath in local_settings['PLUGIN_PATHS']] else: - local_settings = copy.deepcopy(_DEFAULT_CONFIG) - configured_settings = configure_settings(local_settings, None, filename) - return configured_settings + local_settings = copy.deepcopy(DEFAULT_CONFIG) + + if override: + local_settings.update(override) + + parsed_settings = configure_settings(local_settings) + # This is because there doesn't seem to be a way to pass extra + # parameters to docutils directive handlers, so we have to have a + # variable here that we'll import from within Pygments.run (see + # rstdirectives.py) to see what the user defaults were. + global PYGMENTS_RST_OPTIONS + PYGMENTS_RST_OPTIONS = parsed_settings.get('PYGMENTS_RST_OPTIONS', None) + return parsed_settings -def get_settings_from_module(module=None, default_settings=_DEFAULT_CONFIG): - """ - Load settings from a module, returning a dict. - """ +def get_settings_from_module(module=None, default_settings=DEFAULT_CONFIG): + """Loads settings from a module, returns a dictionary.""" context = copy.deepcopy(default_settings) if module is not None: - context.update( - (k, v) for k, v in inspect.getmembers(module) if k.isupper() - ) + context.update( + (k, v) for k, v in inspect.getmembers(module) if k.isupper()) return context -def get_settings_from_file(filename, default_settings=_DEFAULT_CONFIG): - """ - Load settings from a file path, returning a dict. +def get_settings_from_file(path, default_settings=DEFAULT_CONFIG): + """Loads settings from a file path, returning a dict.""" - """ - - name = os.path.basename(filename).rpartition(".")[0] - module = imp.load_source(name, filename) + name, ext = os.path.splitext(os.path.basename(path)) + module = load_source(name, path) return get_settings_from_module(module, default_settings=default_settings) -def configure_settings(settings, default_settings=None, filename=None): - """Provide optimizations, error checking, and warnings for loaded settings""" - if default_settings is None: - default_settings = copy.deepcopy(_DEFAULT_CONFIG) +def configure_settings(settings): + """Provide optimizations, error checking, and warnings for the given + settings. + Also, specify the log messages to be ignored. + """ + if not 'PATH' in settings or not os.path.isdir(settings['PATH']): + raise Exception('You need to specify a path containing the content' + ' (see pelican --help for more information)') - # Make the paths relative to the settings file - if filename: - for path in ['PATH', 'OUTPUT_PATH']: - if path in settings: - if settings[path] is not None and not isabs(settings[path]): - settings[path] = os.path.abspath(os.path.normpath( - os.path.join(os.path.dirname(filename), settings[path])) - ) + # specify the log messages to be ignored + LimitFilter._ignore.update(set(settings.get('LOG_FILTER', + DEFAULT_CONFIG['LOG_FILTER']))) - # if locales is not a list, make it one - locales = settings['LOCALE'] + # lookup the theme in "pelican/themes" if the given one doesn't exist + if not os.path.isdir(settings['THEME']): + theme_path = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + 'themes', + settings['THEME']) + if os.path.exists(theme_path): + settings['THEME'] = theme_path + else: + raise Exception("Could not find the theme %s" + % settings['THEME']) - if isinstance(locales, basestring): - locales = [locales] + # make paths selected for writing absolute if necessary + settings['WRITE_SELECTED'] = [ + os.path.abspath(path) for path in + settings.get('WRITE_SELECTED', DEFAULT_CONFIG['WRITE_SELECTED']) + ] + + # standardize strings to lowercase strings + for key in [ + 'DEFAULT_LANG', + ]: + if key in settings: + settings[key] = settings[key].lower() + + # standardize strings to lists + for key in [ + 'LOCALE', + ]: + if key in settings and isinstance(settings[key], six.string_types): + settings[key] = [settings[key]] + + # check settings that must be a particular type + for key, types in [ + ('OUTPUT_SOURCES_EXTENSION', six.string_types), + ('FILENAME_METADATA', six.string_types), + ]: + if key in settings and not isinstance(settings[key], types): + value = settings.pop(key) + logger.warn('Detected misconfigured %s (%s), ' + 'falling back to the default (%s)', + key, value, DEFAULT_CONFIG[key]) # try to set the different locales, fallback on the default. - if not locales: - locales = _DEFAULT_CONFIG['LOCALE'] + locales = settings.get('LOCALE', DEFAULT_CONFIG['LOCALE']) for locale_ in locales: try: - locale.setlocale(locale.LC_ALL, locale_) + locale.setlocale(locale.LC_ALL, str(locale_)) break # break if it is successful except locale.Error: pass else: - logger.warn("LOCALE option doesn't contain a correct value") + logger.warning("LOCALE option doesn't contain a correct value") if ('SITEURL' in settings): # If SITEURL has a trailing slash, remove it and provide a warning siteurl = settings['SITEURL'] if (siteurl.endswith('/')): settings['SITEURL'] = siteurl[:-1] - logger.warn("Removed extraneous trailing slash from SITEURL.") - # If SITEURL is defined but FEED_DOMAIN isn't, set FEED_DOMAIN = SITEURL + logger.warning("Removed extraneous trailing slash from SITEURL.") + # If SITEURL is defined but FEED_DOMAIN isn't, + # set FEED_DOMAIN to SITEURL if not 'FEED_DOMAIN' in settings: settings['FEED_DOMAIN'] = settings['SITEURL'] + # check content caching layer and warn of incompatibilities + if (settings.get('CACHE_CONTENT', False) and + settings.get('CONTENT_CACHING_LAYER', '') == 'generator' and + settings.get('WITH_FUTURE_DATES', DEFAULT_CONFIG['WITH_FUTURE_DATES'])): + logger.warning('WITH_FUTURE_DATES conflicts with ' + "CONTENT_CACHING_LAYER set to 'generator', " + "use 'reader' layer instead") + # Warn if feeds are generated with both SITEURL & FEED_DOMAIN undefined - if (('FEED_ATOM' in settings) or ('FEED_RSS' in settings)) and (not 'FEED_DOMAIN' in settings): - logger.warn("Since feed URLs should always be absolute, you should specify " - "FEED_DOMAIN in your settings. (e.g., 'FEED_DOMAIN = " - "http://www.example.com')") + feed_keys = [ + 'FEED_ATOM', 'FEED_RSS', + 'FEED_ALL_ATOM', 'FEED_ALL_RSS', + 'CATEGORY_FEED_ATOM', 'CATEGORY_FEED_RSS', + 'AUTHOR_FEED_ATOM', 'AUTHOR_FEED_RSS', + 'TAG_FEED_ATOM', 'TAG_FEED_RSS', + 'TRANSLATION_FEED_ATOM', 'TRANSLATION_FEED_RSS', + ] + + if any(settings.get(k) for k in feed_keys): + if not settings.get('SITEURL'): + logger.warning('Feeds generated without SITEURL set properly may' + ' not be valid') if not 'TIMEZONE' in settings: - logger.warn("No timezone information specified in the settings. Assuming" - " your timezone is UTC for feed generation. Check " - "http://docs.notmyidea.org/alexis/pelican/settings.html#timezone " - "for more information") + logger.warning( + 'No timezone information specified in the settings. Assuming' + ' your timezone is UTC for feed generation. Check ' + 'http://docs.getpelican.com/en/latest/settings.html#timezone ' + 'for more information') - if 'WEBASSETS' in settings and settings['WEBASSETS'] is not False: + # fix up pagination rules + from pelican.paginator import PaginationRule + pagination_rules = [ + PaginationRule(*r) for r in settings.get( + 'PAGINATION_PATTERNS', + DEFAULT_CONFIG['PAGINATION_PATTERNS'], + ) + ] + settings['PAGINATION_PATTERNS'] = sorted( + pagination_rules, + key=lambda r: r[0], + ) + + # move {ARTICLE,PAGE}_DIR -> {ARTICLE,PAGE}_PATHS + for key in ['ARTICLE', 'PAGE']: + old_key = key + '_DIR' + new_key = key + '_PATHS' + if old_key in settings: + logger.warning('Deprecated setting %s, moving it to %s list', + old_key, new_key) + settings[new_key] = [settings[old_key]] # also make a list + del settings[old_key] + + # Save people from accidentally setting a string rather than a list + path_keys = ( + 'ARTICLE_EXCLUDES', + 'DEFAULT_METADATA', + 'DIRECT_TEMPLATES', + 'EXTRA_TEMPLATES_PATHS', + 'FILES_TO_COPY', + 'IGNORE_FILES', + 'JINJA_EXTENSIONS', + 'PAGINATED_DIRECT_TEMPLATES', + 'PLUGINS', + 'STATIC_EXCLUDES', + 'STATIC_PATHS', + 'THEME_STATIC_PATHS', + 'ARTICLE_PATHS', + 'PAGE_PATHS', + ) + for PATH_KEY in filter(lambda k: k in settings, path_keys): + if isinstance(settings[PATH_KEY], six.string_types): + logger.warning("Detected misconfiguration with %s setting " + "(must be a list), falling back to the default", + PATH_KEY) + settings[PATH_KEY] = DEFAULT_CONFIG[PATH_KEY] + + # Add {PAGE,ARTICLE}_PATHS to {ARTICLE,PAGE}_EXCLUDES + mutually_exclusive = ('ARTICLE', 'PAGE') + for type_1, type_2 in [mutually_exclusive, mutually_exclusive[::-1]]: try: - from webassets.ext.jinja2 import AssetsExtension - settings['JINJA_EXTENSIONS'].append(AssetsExtension) - except ImportError: - logger.warn("You must install the webassets module to use WEBASSETS.") - settings['WEBASSETS'] = False + includes = settings[type_1 + '_PATHS'] + excludes = settings[type_2 + '_EXCLUDES'] + for path in includes: + if path not in excludes: + excludes.append(path) + except KeyError: + continue # setting not specified, nothing to do - if 'OUTPUT_SOURCES_EXTENSION' in settings: - if not isinstance(settings['OUTPUT_SOURCES_EXTENSION'], str): - settings['OUTPUT_SOURCES_EXTENSION'] = _DEFAULT_CONFIG['OUTPUT_SOURCES_EXTENSION'] - logger.warn("Detected misconfiguration with OUTPUT_SOURCES_EXTENSION." - " falling back to the default extension " + - _DEFAULT_CONFIG['OUTPUT_SOURCES_EXTENSION']) + for old, new, doc in [ + ('LESS_GENERATOR', 'the Webassets plugin', None), + ('FILES_TO_COPY', 'STATIC_PATHS and EXTRA_PATH_METADATA', + 'https://github.com/getpelican/pelican/blob/master/docs/settings.rst#path-metadata'), + ]: + if old in settings: + message = 'The {} setting has been removed in favor of {}'.format( + old, new) + if doc: + message += ', see {} for details'.format(doc) + logger.warning(message) return settings diff --git a/pelican/signals.py b/pelican/signals.py index f3e16e76..f858c249 100644 --- a/pelican/signals.py +++ b/pelican/signals.py @@ -1,10 +1,47 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function from blinker import signal +# Run-level signals: + initialized = signal('pelican_initialized') -finalized = signal('pelican_finalized') -article_generate_context = signal('article_generate_context') -article_generator_init = signal('article_generator_init') get_generators = signal('get_generators') -pages_generate_context = signal('pages_generate_context') -pages_generator_init = signal('pages_generator_init') +get_writer = signal('get_writer') +finalized = signal('pelican_finalized') + +# Reader-level signals + +readers_init = signal('readers_init') + +# Generator-level signals + +generator_init = signal('generator_init') + +article_generator_init = signal('article_generator_init') +article_generator_pretaxonomy = signal('article_generator_pretaxonomy') +article_generator_finalized = signal('article_generator_finalized') +article_generator_write_article = signal('article_generator_write_article') +article_writer_finalized = signal('article_writer_finalized') + +page_generator_init = signal('page_generator_init') +page_generator_finalized = signal('page_generator_finalized') + +static_generator_init = signal('static_generator_init') +static_generator_finalized = signal('static_generator_finalized') + +# Page-level signals + +article_generator_preread = signal('article_generator_preread') +article_generator_context = signal('article_generator_context') + +page_generator_preread = signal('page_generator_preread') +page_generator_context = signal('page_generator_context') + +static_generator_preread = signal('static_generator_preread') +static_generator_context = signal('static_generator_context') + content_object_init = signal('content_object_init') + +# Writers signals +content_written = signal('content_written') +feed_written = signal('feed_written') diff --git a/tests/TestPages/bad_page.rst b/pelican/tests/TestPages/bad_page.rst similarity index 100% rename from tests/TestPages/bad_page.rst rename to pelican/tests/TestPages/bad_page.rst diff --git a/tests/TestPages/hidden_page.rst b/pelican/tests/TestPages/hidden_page.rst similarity index 100% rename from tests/TestPages/hidden_page.rst rename to pelican/tests/TestPages/hidden_page.rst diff --git a/tests/TestPages/hidden_page_markdown.md b/pelican/tests/TestPages/hidden_page_markdown.md similarity index 100% rename from tests/TestPages/hidden_page_markdown.md rename to pelican/tests/TestPages/hidden_page_markdown.md diff --git a/tests/TestPages/hidden_page_with_template.rst b/pelican/tests/TestPages/hidden_page_with_template.rst similarity index 100% rename from tests/TestPages/hidden_page_with_template.rst rename to pelican/tests/TestPages/hidden_page_with_template.rst diff --git a/tests/TestPages/page.rst b/pelican/tests/TestPages/page.rst similarity index 100% rename from tests/TestPages/page.rst rename to pelican/tests/TestPages/page.rst diff --git a/tests/TestPages/page_markdown.md b/pelican/tests/TestPages/page_markdown.md similarity index 100% rename from tests/TestPages/page_markdown.md rename to pelican/tests/TestPages/page_markdown.md diff --git a/pelican/tests/TestPages/page_used_for_sorting_test.rst b/pelican/tests/TestPages/page_used_for_sorting_test.rst new file mode 100644 index 00000000..40cdc7ea --- /dev/null +++ b/pelican/tests/TestPages/page_used_for_sorting_test.rst @@ -0,0 +1,6 @@ +A Page (Test) for sorting +######################### + +:slug: zzzz + +When using title, should be first. When using slug, should be last. diff --git a/tests/TestPages/page_with_template.rst b/pelican/tests/TestPages/page_with_template.rst similarity index 100% rename from tests/TestPages/page_with_template.rst rename to pelican/tests/TestPages/page_with_template.rst diff --git a/pelican/tests/__init__.py b/pelican/tests/__init__.py new file mode 100644 index 00000000..32353ea2 --- /dev/null +++ b/pelican/tests/__init__.py @@ -0,0 +1,2 @@ +import logging +logging.getLogger().addHandler(logging.NullHandler()) diff --git a/pelican/tests/content/2012-11-29_rst_w_filename_meta#foo-bar.rst b/pelican/tests/content/2012-11-29_rst_w_filename_meta#foo-bar.rst new file mode 100644 index 00000000..43f05a15 --- /dev/null +++ b/pelican/tests/content/2012-11-29_rst_w_filename_meta#foo-bar.rst @@ -0,0 +1,6 @@ + +Rst with filename metadata +########################## + +:category: yeah +:author: Alexis Métaireau diff --git a/pelican/tests/content/2012-11-30_md_w_filename_meta#foo-bar.md b/pelican/tests/content/2012-11-30_md_w_filename_meta#foo-bar.md new file mode 100644 index 00000000..cdccfc8a --- /dev/null +++ b/pelican/tests/content/2012-11-30_md_w_filename_meta#foo-bar.md @@ -0,0 +1,6 @@ +category: yeah +author: Alexis Métaireau + +Markdown with filename metadata +=============================== + diff --git a/tests/content/TestCategory/article_with_category.rst b/pelican/tests/content/TestCategory/article_with_category.rst similarity index 87% rename from tests/content/TestCategory/article_with_category.rst rename to pelican/tests/content/TestCategory/article_with_category.rst index 7ed6e6d1..69ffa98b 100644 --- a/tests/content/TestCategory/article_with_category.rst +++ b/pelican/tests/content/TestCategory/article_with_category.rst @@ -2,5 +2,6 @@ This is an article with category ! ################################## :category: yeah +:date: 1970-01-01 This article should be in 'yeah' category. diff --git a/tests/content/TestCategory/article_without_category.rst b/pelican/tests/content/TestCategory/article_without_category.rst similarity index 100% rename from tests/content/TestCategory/article_without_category.rst rename to pelican/tests/content/TestCategory/article_without_category.rst diff --git a/tests/content/article.rst b/pelican/tests/content/article.rst similarity index 62% rename from tests/content/article.rst rename to pelican/tests/content/article.rst index 7109c29b..793e6869 100644 --- a/tests/content/article.rst +++ b/pelican/tests/content/article.rst @@ -1,6 +1,6 @@ Article title ############# -This is some content. With some stuff to "typogrify". +THIS is some content. With some stuff to "typogrify"... Now with added support for :abbr:`TLA (three letter acronym)`. diff --git a/pelican/tests/content/article_with_code_block.rst b/pelican/tests/content/article_with_code_block.rst new file mode 100644 index 00000000..586878cf --- /dev/null +++ b/pelican/tests/content/article_with_code_block.rst @@ -0,0 +1,15 @@ +An Article With Code Block To Test Typogrify Ignore +################################################### + +An article with some code + +.. code-block:: python + + x & y + +A block quote: + + x & y + +Normal: +x & y diff --git a/pelican/tests/content/article_with_comments.html b/pelican/tests/content/article_with_comments.html new file mode 100644 index 00000000..289e4a66 --- /dev/null +++ b/pelican/tests/content/article_with_comments.html @@ -0,0 +1,8 @@ + + + + + Body content + + + diff --git a/pelican/tests/content/article_with_keywords.html b/pelican/tests/content/article_with_keywords.html new file mode 100644 index 00000000..0744c754 --- /dev/null +++ b/pelican/tests/content/article_with_keywords.html @@ -0,0 +1,6 @@ + + + This is a super article ! + + + diff --git a/pelican/tests/content/article_with_markdown_and_footnote.md b/pelican/tests/content/article_with_markdown_and_footnote.md new file mode 100644 index 00000000..6fea2d6e --- /dev/null +++ b/pelican/tests/content/article_with_markdown_and_footnote.md @@ -0,0 +1,15 @@ +Title: Article with markdown containing footnotes +Date: 2012-10-31 +Modified: 2012-11-01 +Summary: Summary with **inline** markup *should* be supported. +Multiline: Line Metadata should be handle properly. + See syntax of Meta-Data extension of Python Markdown package: + If a line is indented by 4 or more spaces, + that line is assumed to be an additional line of the value + for the previous keyword. + A keyword may have as many lines as desired. + +This is some content[^1] with some footnotes[^footnote] + +[^1]: Numbered footnote +[^footnote]: Named footnote diff --git a/pelican/tests/content/article_with_markdown_and_nonascii_summary.md b/pelican/tests/content/article_with_markdown_and_nonascii_summary.md new file mode 100644 index 00000000..d76ed4a1 --- /dev/null +++ b/pelican/tests/content/article_with_markdown_and_nonascii_summary.md @@ -0,0 +1,19 @@ +Title: マックOS X 10.8でパイソンとVirtualenvをインストールと設定 +Slug: python-virtualenv-on-mac-osx-mountain-lion-10.8 +Date: 2012-12-20 +Modified: 2012-12-22 +Tags: パイソン, マック +Category: 指導書 +Summary: パイソンとVirtualenvをまっくでインストールする方法について明確に説明します。 + +Writing unicode is certainly fun. + +パイソンとVirtualenvをまっくでインストールする方法について明確に説明します。 + +And let's mix languages. + +первый пост + +Now another. + +İlk yazı çok özel değil. diff --git a/pelican/tests/content/article_with_markdown_and_summary_metadata_multi.md b/pelican/tests/content/article_with_markdown_and_summary_metadata_multi.md new file mode 100644 index 00000000..b6ef666c --- /dev/null +++ b/pelican/tests/content/article_with_markdown_and_summary_metadata_multi.md @@ -0,0 +1,7 @@ +Title: Article with markdown and summary metadata multi +Date: 2012-10-31 +Summary: + A multi-line summary should be supported + as well as **inline markup**. + +This is some content. diff --git a/pelican/tests/content/article_with_markdown_and_summary_metadata_single.md b/pelican/tests/content/article_with_markdown_and_summary_metadata_single.md new file mode 100644 index 00000000..a7d6f09b --- /dev/null +++ b/pelican/tests/content/article_with_markdown_and_summary_metadata_single.md @@ -0,0 +1,5 @@ +Title: Article with markdown and summary metadata single +Date: 2012-10-30 +Summary: A single-line summary should be supported as well as **inline markup**. + +This is some content. diff --git a/pelican/tests/content/article_with_markdown_extension.markdown b/pelican/tests/content/article_with_markdown_extension.markdown new file mode 100644 index 00000000..94e92871 --- /dev/null +++ b/pelican/tests/content/article_with_markdown_extension.markdown @@ -0,0 +1,10 @@ +title: Test markdown File +category: test + +Test Markdown File Header +========================= + +Used for pelican test +--------------------- + +This is another markdown test file. Uses the markdown extension. diff --git a/tests/content/article_with_markdown_markup_extensions.md b/pelican/tests/content/article_with_markdown_markup_extensions.md similarity index 100% rename from tests/content/article_with_markdown_markup_extensions.md rename to pelican/tests/content/article_with_markdown_markup_extensions.md diff --git a/pelican/tests/content/article_with_md_extension.md b/pelican/tests/content/article_with_md_extension.md new file mode 100644 index 00000000..89b6980c --- /dev/null +++ b/pelican/tests/content/article_with_md_extension.md @@ -0,0 +1,14 @@ +Title: Test md File +Category: test +Tags: foo, bar, foobar +Date: 2010-12-02 10:14 +Modified: 2010-12-02 10:20 +Summary: I have a lot to test + +Test Markdown File Header +========================= + +Used for pelican test +--------------------- + +The quick brown fox jumped over the lazy dog's back. diff --git a/tests/content/article_with_md_extension.md b/pelican/tests/content/article_with_mdown_extension.mdown similarity index 57% rename from tests/content/article_with_md_extension.md rename to pelican/tests/content/article_with_mdown_extension.mdown index 11aa22a2..bdaf74cd 100644 --- a/tests/content/article_with_md_extension.md +++ b/pelican/tests/content/article_with_mdown_extension.mdown @@ -1,4 +1,4 @@ -title: Test md File +title: Test mdown File category: test Test Markdown File Header @@ -7,4 +7,4 @@ Test Markdown File Header Used for pelican test --------------------- -The quick brown fox jumped over the lazy dog's back. +This is another markdown test file. Uses the mdown extension. diff --git a/pelican/tests/content/article_with_metadata.html b/pelican/tests/content/article_with_metadata.html new file mode 100644 index 00000000..b501ea29 --- /dev/null +++ b/pelican/tests/content/article_with_metadata.html @@ -0,0 +1,15 @@ + + + This is a super article ! + + + + + + + + + Multi-line metadata should be supported + as well as inline markup. + + diff --git a/pelican/tests/content/article_with_metadata.rst b/pelican/tests/content/article_with_metadata.rst new file mode 100644 index 00000000..9b65a4b0 --- /dev/null +++ b/pelican/tests/content/article_with_metadata.rst @@ -0,0 +1,13 @@ + +This is a super article ! +######################### + +:tags: foo, bar, foobar +:date: 2010-12-02 10:14 +:modified: 2010-12-02 10:20 +:category: yeah +:author: Alexis Métaireau +:summary: + Multi-line metadata should be supported + as well as **inline markup** and stuff to "typogrify"... +:custom_field: http://notmyidea.org diff --git a/tests/content/article_with_metadata.rst b/pelican/tests/content/article_with_metadata.unknownextension similarity index 100% rename from tests/content/article_with_metadata.rst rename to pelican/tests/content/article_with_metadata.unknownextension diff --git a/pelican/tests/content/article_with_metadata_and_contents.html b/pelican/tests/content/article_with_metadata_and_contents.html new file mode 100644 index 00000000..b108ac8a --- /dev/null +++ b/pelican/tests/content/article_with_metadata_and_contents.html @@ -0,0 +1,15 @@ + + + This is a super article ! + + + + + + + + + Multi-line metadata should be supported + as well as inline markup. + + diff --git a/tests/content/article_with_mkd_extension.mkd b/pelican/tests/content/article_with_mkd_extension.mkd similarity index 100% rename from tests/content/article_with_mkd_extension.mkd rename to pelican/tests/content/article_with_mkd_extension.mkd diff --git a/pelican/tests/content/article_with_multiple_authors.html b/pelican/tests/content/article_with_multiple_authors.html new file mode 100644 index 00000000..a74442c9 --- /dev/null +++ b/pelican/tests/content/article_with_multiple_authors.html @@ -0,0 +1,6 @@ + + + This is an article with multiple authors! + + + diff --git a/pelican/tests/content/article_with_multiple_authors.rst b/pelican/tests/content/article_with_multiple_authors.rst new file mode 100644 index 00000000..04af017c --- /dev/null +++ b/pelican/tests/content/article_with_multiple_authors.rst @@ -0,0 +1,6 @@ +This is an article with multiple authors! +######################################### + +:date: 2014-02-09 02:20 +:modified: 2014-02-09 02:20 +:authors: First Author, Second Author diff --git a/pelican/tests/content/article_with_nonconformant_meta_tags.html b/pelican/tests/content/article_with_nonconformant_meta_tags.html new file mode 100644 index 00000000..5ed44bbd --- /dev/null +++ b/pelican/tests/content/article_with_nonconformant_meta_tags.html @@ -0,0 +1,12 @@ + + + + + Article with Nonconformant HTML meta tags + + + + Multi-line metadata should be supported + as well as inline markup. + + diff --git a/pelican/tests/content/article_with_null_attributes.html b/pelican/tests/content/article_with_null_attributes.html new file mode 100644 index 00000000..68da704c --- /dev/null +++ b/pelican/tests/content/article_with_null_attributes.html @@ -0,0 +1,8 @@ + + + + + Ensure that empty attributes are copied properly. + + + diff --git a/tests/content/article_with_template.rst b/pelican/tests/content/article_with_template.rst similarity index 100% rename from tests/content/article_with_template.rst rename to pelican/tests/content/article_with_template.rst diff --git a/pelican/tests/content/article_with_uppercase_metadata.html b/pelican/tests/content/article_with_uppercase_metadata.html new file mode 100644 index 00000000..b4cedf39 --- /dev/null +++ b/pelican/tests/content/article_with_uppercase_metadata.html @@ -0,0 +1,6 @@ + + + This is a super article ! + + + diff --git a/tests/content/article_with_uppercase_metadata.rst b/pelican/tests/content/article_with_uppercase_metadata.rst similarity index 100% rename from tests/content/article_with_uppercase_metadata.rst rename to pelican/tests/content/article_with_uppercase_metadata.rst diff --git a/tests/content/article_without_category.rst b/pelican/tests/content/article_without_category.rst similarity index 100% rename from tests/content/article_without_category.rst rename to pelican/tests/content/article_without_category.rst diff --git a/pelican/tests/content/wordpress_content_decoded b/pelican/tests/content/wordpress_content_decoded new file mode 100644 index 00000000..6e91338c --- /dev/null +++ b/pelican/tests/content/wordpress_content_decoded @@ -0,0 +1,48 @@ +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

      +

      +

      +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

      +
        +
      • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      • +
      • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      • +
      +
      +
      +  a = [1, 2, 3]
      +  b = [4, 5, 6]
      +  for i in zip(a, b):
      +    print i
      +
      +
      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

      diff --git a/pelican/tests/content/wordpress_content_encoded b/pelican/tests/content/wordpress_content_encoded new file mode 100644 index 00000000..da35de3b --- /dev/null +++ b/pelican/tests/content/wordpress_content_encoded @@ -0,0 +1,55 @@ +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + + + +
      +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum. +
      +
        +
      • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      • +
      • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      • +
      + +
      +
      +  a = [1, 2, 3]
      +  b = [4, 5, 6]
      +  for i in zip(a, b):
      +    print i
      +
      +
      + +Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + diff --git a/tests/content/wordpressexport.xml b/pelican/tests/content/wordpressexport.xml similarity index 65% rename from tests/content/wordpressexport.xml rename to pelican/tests/content/wordpressexport.xml index d3e86cba..686b0fa7 100644 --- a/tests/content/wordpressexport.xml +++ b/pelican/tests/content/wordpressexport.xml @@ -112,10 +112,10 @@ A normal post - http://thisisa.test/?p=173 + http://thisisa.test/?p=174 Thu, 01 Jan 1970 00:00:00 +0000 bob - http://thisisa.test/?p=173 + http://thisisa.test/?p=174 - 173 + 174 2012-02-16 15:52:55 0000-00-00 00:00:00 open @@ -574,5 +574,380 @@ Bottom line: don't mess up with birds]]> - + + A normal post with some <html> entities in the title. You can't miss them. + http://thisisa.test/?p=175 + Thu, 01 Jan 1970 00:00:00 +0000 + bob + http://thisisa.test/?p=175 + + +
    • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    • +
    • Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod +tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, +quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo +consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse +cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non +proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    • +