mirror of
https://github.com/getpelican/pelican.git
synced 2025-10-15 20:28:56 +02:00
Merge branch 'master' into hidden-posts
This commit is contained in:
commit
05c9c1f617
82 changed files with 735 additions and 413 deletions
|
|
@ -11,5 +11,5 @@ trim_trailing_whitespace = true
|
|||
[*.py]
|
||||
max_line_length = 79
|
||||
|
||||
[*.yml]
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
|
|
|||
16
.github/workflows/main.yml
vendored
16
.github/workflows/main.yml
vendored
|
|
@ -15,14 +15,14 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- os: ubuntu
|
||||
python: 3.5
|
||||
- os: ubuntu
|
||||
python: 3.6
|
||||
- os: ubuntu
|
||||
python: 3.7
|
||||
- os: ubuntu
|
||||
python: 3.8
|
||||
- os: ubuntu
|
||||
python: 3.9
|
||||
- os: macos
|
||||
python: 3.7
|
||||
- os: windows
|
||||
|
|
@ -31,7 +31,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Python ${{ matrix.config.python }}
|
||||
uses: actions/setup-python@v1.1.1
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.config.python }}
|
||||
- name: Set pip cache (Linux)
|
||||
|
|
@ -84,9 +84,9 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v1.1.1
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.6
|
||||
python-version: 3.7
|
||||
- name: Set pip cache (Linux)
|
||||
uses: actions/cache@v1
|
||||
if: startsWith(runner.os, 'Linux')
|
||||
|
|
@ -108,9 +108,9 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v1.1.1
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.6
|
||||
python-version: 3.7
|
||||
- name: Set pip cache (Linux)
|
||||
uses: actions/cache@v1
|
||||
if: startsWith(runner.os, 'Linux')
|
||||
|
|
@ -134,7 +134,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v1.1.1
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.7
|
||||
- name: Check release
|
||||
|
|
|
|||
53
.travis.yml
53
.travis.yml
|
|
@ -1,53 +0,0 @@
|
|||
language: python
|
||||
python:
|
||||
- "3.6"
|
||||
env:
|
||||
global:
|
||||
- PYPI_USERNAME=autopub
|
||||
- secure: "h5V/+YL+CrqvfAesNkSb824Ngk5x+f0eFzj/LBbmnzjvArKAmc6R6WGyx8SDD7WF/PlaTf0M1fH3a7pjIS8Ee+TS1Rb0Lt1HPqUs1yntg1+Js2ZQp3p20wfsDc+bZ4/2g8xLsSMv1EJ4np7/GJ5fXqpSxjr/Xs5LYA7ZLwNNwDw="
|
||||
- secure: "GiDFfmjH7uzYNnkjQMV/mIkbRdmgkGmtbFPeaj9taBNA5tPp3IBt3GOOS6UL/zm9xiwu9Xo6sxZWkGzY19Hsdv28YPH34N3abo0QSnz4IGiHs152Hi7Qi6Tb0QkT5D3OxuSIm8LmFL7+su89Q7vBFowrT6HL1Mn8CDDWSj3eqbo="
|
||||
- TWINE_USERNAME=$PYPI_USERNAME
|
||||
- TWINE_PASSWORD=$PYPI_PASSWORD
|
||||
matrix:
|
||||
- TOX_ENV=docs
|
||||
- TOX_ENV=flake8
|
||||
- TOX_ENV=py3.5
|
||||
- TOX_ENV=py3.6
|
||||
matrix:
|
||||
include:
|
||||
- python: 3.7
|
||||
sudo: true
|
||||
dist: xenial
|
||||
env:
|
||||
- TOX_ENV=py3.7
|
||||
addons:
|
||||
apt_packages:
|
||||
- pandoc
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo locale-gen fr_FR.UTF-8 tr_TR.UTF-8
|
||||
install:
|
||||
- pip install tox==2.5.0
|
||||
script: tox -e $TOX_ENV
|
||||
before_deploy:
|
||||
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then travis_terminate 0; fi'
|
||||
- pip install githubrelease
|
||||
- pip install --pre autopub
|
||||
- autopub check || travis_terminate 0
|
||||
- pip install poetry
|
||||
- pip install twine
|
||||
- git checkout ${TRAVIS_BRANCH}
|
||||
- git remote set-url origin https://$GITHUB_TOKEN@github.com/$TRAVIS_REPO_SLUG
|
||||
deploy:
|
||||
provider: script
|
||||
script: autopub deploy
|
||||
skip_cleanup: true
|
||||
on:
|
||||
branch: master
|
||||
python: "3.7"
|
||||
# The channel name "irc.freenode.org#pelican" is encrypted against getpelican/pelican to prevent IRC spam of forks
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- secure: "JP57f61QovrhmLoAF6oPOzIK2aXGfSO06FHg7yiuKBOWMiaxQejZUGJX919muCLhWJXDugsviIqCMoAWwNV3o1WQbqIr+G5TR+N9MrtCs4Zi6vpGj09bR8giKUKx+PPKEoe1Ew56E4y2LxzGO4Lj9hZx8M2YVdwPNWrWZgp6WXE="
|
||||
on_success: change
|
||||
|
|
@ -43,7 +43,7 @@ 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``).
|
||||
it (the full command you used, e.g. ``python -m 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
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
include *.rst
|
||||
recursive-include pelican *.html *.css *png *.rst *.markdown *.md *.mkd *.xml *.py
|
||||
recursive-include pelican *.html *.css *png *.rst *.markdown *.md *.mkd *.xml *.py *.jinja2
|
||||
include LICENSE THANKS docs/changelog.rst pyproject.toml
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Pelican |build-status| |pypi-version| |repology|
|
||||
=====================================
|
||||
================================================
|
||||
|
||||
Pelican is a static site generator, written in Python_.
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ Why the name "Pelican"?
|
|||
:target: https://github.com/getpelican/pelican/actions
|
||||
:alt: GitHub Actions CI: continuous integration status
|
||||
.. |pypi-version| image:: https://img.shields.io/pypi/v/pelican.svg
|
||||
:target: https://pypi.python.org/pypi/pelican
|
||||
:target: https://pypi.org/project/pelican/
|
||||
:alt: PyPI: the Python Package Index
|
||||
.. |repology| image:: https://repology.org/badge/tiny-repos/pelican.svg
|
||||
:target: https://repology.org/project/pelican/versions
|
||||
|
|
|
|||
1
THANKS
1
THANKS
|
|
@ -97,6 +97,7 @@ Kyle Fuller
|
|||
Laureline Guerin
|
||||
Leonard Huang
|
||||
Leroy Jiang
|
||||
Lucas Cimon
|
||||
Marcel Hellkamp
|
||||
Marco Milanesi
|
||||
Marcus Fredriksson
|
||||
|
|
|
|||
|
|
@ -1,6 +1,52 @@
|
|||
Release history
|
||||
###############
|
||||
|
||||
4.6.0 - 2021-03-23
|
||||
==================
|
||||
|
||||
* Add new URL pattern to ``PAGINATION_PATTERNS`` for the last page in the list `(#1401) <https://github.com/getpelican/pelican/issues/1401>`_
|
||||
* Speed up ``livereload`` Invoke task via caching `(#2847) <https://github.com/getpelican/pelican/pull/2847>`_
|
||||
* Ignore ``None`` return value from ``get_generators`` signal `(#2850) <https://github.com/getpelican/pelican/pull/2850>`_
|
||||
* Relax dependency minimum versions and remove upper bounds
|
||||
|
||||
4.5.4 - 2021-01-04
|
||||
==================
|
||||
|
||||
Replace plugin definitions in settings with string representations after registering, so they can be cached correctly `(#2828) <https://github.com/getpelican/pelican/issues/2828>`_.
|
||||
|
||||
4.5.3 - 2020-12-01
|
||||
==================
|
||||
|
||||
Fix a mistake made in PR #2821
|
||||
|
||||
4.5.2 - 2020-11-22
|
||||
==================
|
||||
|
||||
Improve logging of generators and writer loaders
|
||||
|
||||
4.5.1 - 2020-11-02
|
||||
==================
|
||||
|
||||
* Refactor intra-site link discovery in order to match more permissively `(#2646) <https://github.com/getpelican/pelican/issues/2646>`_
|
||||
* Fix plugins running twice in auto-reload mode `(#2817) <https://github.com/getpelican/pelican/issues/2817>`_
|
||||
* Add notice to use ``from pelican import signals`` instead of ``import pelican.signals`` `(#2805) <https://github.com/getpelican/pelican/issues/2805>`_
|
||||
|
||||
4.5.0 - 2020-08-20
|
||||
==================
|
||||
|
||||
* Add namespace plugin support; list plugins via ``pelican-plugins`` command
|
||||
* Override settings via ``-e`` / ``--extra-settings`` CLI option flags
|
||||
* Add settings for custom Jinja globals and tests
|
||||
* Customize article summary ellipsis via ``SUMMARY_END_SUFFIX`` setting
|
||||
* Customize Typogrify dash handling via new ``TYPOGRIFY_DASHES`` setting
|
||||
* Support Unicode when generating slugs
|
||||
* Support Asciidoc ``.adoc`` file generation in Pelican importer
|
||||
* Improve user experience when ``pelican --listen`` web server is quit
|
||||
* Improve Invoke tasks template
|
||||
* Include tests in source distributions
|
||||
* Switch CI from Travis to GitHub Actions
|
||||
* Remove support for Python 2.7
|
||||
|
||||
4.2.0 - 2019-10-17
|
||||
==================
|
||||
|
||||
|
|
@ -12,7 +58,7 @@ Release history
|
|||
4.1.3 - 2019-10-09
|
||||
==================
|
||||
|
||||
* Fix quick-start docs regarding `pelican --listen`
|
||||
* Fix quick-start docs regarding ``pelican --listen``
|
||||
* Set default listen address to 127.0.0.1
|
||||
* Add extra/optional Markdown dependency to setup.py
|
||||
* Use correct SSH port syntax for rsync in tasks.py
|
||||
|
|
@ -30,8 +76,8 @@ Fix pelican.settings.load_source to avoid caching issues - PR #2621
|
|||
|
||||
* Add AutoPub to auto-publish releases on PR merge
|
||||
* Add CSS classes for reStructuredText figures
|
||||
* Pass `argv` to Pelican `main` entrypoint
|
||||
* Set default content status to a blank string rather than `None`
|
||||
* Pass ``argv`` to Pelican ``main`` entrypoint
|
||||
* Set default content status to a blank string rather than ``None``
|
||||
|
||||
4.1.0 - 2019-07-14
|
||||
==================
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ to manually create and activate a virtual environment::
|
|||
|
||||
Install the needed dependencies and set up the project::
|
||||
|
||||
pip install invoke
|
||||
python -m pip install invoke
|
||||
invoke setup
|
||||
pip install -e ~/projects/pelican
|
||||
python -m pip install -e ~/projects/pelican
|
||||
|
||||
Your local environment should now be ready to go!
|
||||
|
||||
|
|
@ -75,11 +75,14 @@ via::
|
|||
|
||||
invoke tests
|
||||
|
||||
In addition to running the test suite, the above invocation will also check code
|
||||
style and let you know whether non-conforming patterns were found. In some cases
|
||||
these linters will make the needed changes directly, while in other cases you
|
||||
may need to make additional changes until ``invoke tests`` no longer reports any
|
||||
code style violations.
|
||||
In addition to running the test suite, it is important to also ensure that any
|
||||
lines you changed conform to code style guidelines. You can check that via::
|
||||
|
||||
invoke lint
|
||||
|
||||
If code style violations are found in lines you changed, correct those lines
|
||||
and re-run the above lint command until they have all been fixed. You do not
|
||||
need to address style violations, if any, for code lines you did not touch.
|
||||
|
||||
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
|
||||
|
|
@ -145,9 +148,20 @@ Create a topic branch for your plugin bug fix or feature::
|
|||
|
||||
git checkout -b name-of-your-bugfix-or-feature
|
||||
|
||||
After writing new tests for your plugin changes, run the plugin test suite::
|
||||
After writing new tests for your plugin changes, run the plugin test suite and
|
||||
check for code style compliance via::
|
||||
|
||||
invoke tests
|
||||
invoke lint
|
||||
|
||||
If style violations are found, many of them can be addressed automatically via::
|
||||
|
||||
invoke black
|
||||
invoke isort
|
||||
|
||||
If style violations are found even after running the above auto-formatters,
|
||||
you will need to make additional manual changes until ``invoke lint`` no longer
|
||||
reports any code style violations.
|
||||
|
||||
.. _plugin template: https://github.com/getpelican/cookiecutter-pelican-plugin
|
||||
.. _Simple Footnotes: https://github.com/pelican-plugins/simple-footnotes
|
||||
|
|
|
|||
45
docs/faq.rst
45
docs/faq.rst
|
|
@ -74,7 +74,7 @@ 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::
|
||||
|
||||
pip install markdown
|
||||
python -m pip install markdown
|
||||
|
||||
Can I use arbitrary metadata in my templates?
|
||||
=============================================
|
||||
|
|
@ -174,28 +174,18 @@ your site.
|
|||
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.x
|
||||
===================================================
|
||||
Can I force Atom feeds to show only summaries instead of article content?
|
||||
=========================================================================
|
||||
|
||||
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 settings::
|
||||
|
||||
FEED -> FEED_ATOM
|
||||
TAG_FEED -> TAG_FEED_ATOM
|
||||
CATEGORY_FEED -> CATEGORY_FEED_ATOM
|
||||
|
||||
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.
|
||||
Instead of having to open a separate browser window to read articles, the
|
||||
overwhelming majority of folks who use feed readers prefer to read content
|
||||
within the feed reader itself. Mainly for that reason, Pelican does not support
|
||||
restricting Atom feeds to only contain summaries. Unlike Atom feeds, the RSS
|
||||
feed specification does not include a separate ``content`` field, so by default
|
||||
Pelican publishes RSS feeds that only contain summaries (but can optionally be
|
||||
set to instead publish full content RSS feeds). So the default feed generation
|
||||
behavior provides users with a choice: subscribe to Atom feeds for full content
|
||||
or to RSS feeds for just the summaries.
|
||||
|
||||
Is Pelican only suitable for blogs?
|
||||
===================================
|
||||
|
|
@ -228,7 +218,7 @@ 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
|
||||
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?
|
||||
|
|
@ -242,11 +232,10 @@ command similar to ``cd content; find -name '*.md' | head -n 10``.
|
|||
My tag-cloud is missing/broken since I upgraded Pelican
|
||||
=======================================================
|
||||
|
||||
In an ongoing effort to steamline Pelican, `tag_cloud` generation has been
|
||||
moved out of the pelican core and into a separate `plugin
|
||||
<https://github.com/getpelican/pelican-plugins/tree/master/tag_cloud>`_. See
|
||||
the :ref:`plugins` documentation further information about the Pelican plugin
|
||||
system.
|
||||
In an ongoing effort to streamline Pelican, tag cloud generation has been
|
||||
moved out of Pelican core and into a separate `plugin
|
||||
<https://github.com/pelican-plugins/tag-cloud>`_. See the :ref:`plugins`
|
||||
documentation for further information about the Pelican plugin system.
|
||||
|
||||
Since I upgraded Pelican my pages are no longer rendered
|
||||
========================================================
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ not be converted (as Pelican also supports Markdown).
|
|||
|
||||
Unlike Pelican, Wordpress supports multiple categories per article. These
|
||||
are imported as a comma-separated string. You have to resolve these
|
||||
manually, or use a plugin that enables multiple categories per article
|
||||
(like `more_categories`_).
|
||||
manually, or use a plugin such as `More Categories`_ that enables multiple
|
||||
categories per article.
|
||||
|
||||
Dependencies
|
||||
============
|
||||
|
|
@ -140,4 +140,4 @@ To test the module, one can use sample files:
|
|||
- for WordPress: https://www.wpbeginner.com/wp-themes/how-to-add-dummy-content-for-theme-development-in-wordpress/
|
||||
- for Dotclear: http://media.dotaddict.org/tda/downloads/lorem-backup.txt
|
||||
|
||||
.. _more_categories: https://github.com/getpelican/pelican-plugins/tree/master/more_categories
|
||||
.. _More Categories: https://github.com/pelican-plugins/more-categories
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
Installing Pelican
|
||||
##################
|
||||
|
||||
Pelican currently runs best on Python 2.7.x and 3.5+; earlier versions of
|
||||
Python are not supported.
|
||||
Pelican currently runs best on 3.6+; earlier versions of Python are not supported.
|
||||
|
||||
You can install Pelican via several different methods. The simplest is via
|
||||
`pip <https://pip.pypa.io/en/stable/>`_::
|
||||
You can install Pelican via several different methods. The simplest is via Pip_::
|
||||
|
||||
pip install pelican
|
||||
python -m pip install pelican
|
||||
|
||||
Or, if you plan on using Markdown::
|
||||
|
||||
pip install pelican[Markdown]
|
||||
python -m pip install "pelican[markdown]"
|
||||
|
||||
(Keep in mind that operating systems will often require you to prefix the above
|
||||
(Keep in mind that some operating systems will 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
|
||||
|
|
@ -26,7 +24,7 @@ session and create a new virtual environment for Pelican::
|
|||
source bin/activate
|
||||
|
||||
Once the virtual environment has been created and activated, Pelican can be
|
||||
installed via ``pip install pelican`` as noted above. Alternatively, if you
|
||||
installed via ``python -m 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
|
||||
|
|
@ -35,7 +33,7 @@ have the project source, you can install Pelican using the distutils method::
|
|||
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"
|
||||
python -m 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<publish>` section.
|
||||
|
|
@ -46,17 +44,13 @@ Optional packages
|
|||
If you plan on using `Markdown <https://pypi.org/project/Markdown/>`_ as a
|
||||
markup format, you can install Pelican with Markdown support::
|
||||
|
||||
pip install pelican[Markdown]
|
||||
|
||||
Or you might need to install it a posteriori::
|
||||
|
||||
pip install Markdown
|
||||
python -m pip install "pelican[markdown]"
|
||||
|
||||
Typographical enhancements can be enabled in your settings file, but first the
|
||||
requisite `Typogrify <https://pypi.org/project/typogrify/>`_ library must be
|
||||
installed::
|
||||
|
||||
pip install typogrify
|
||||
python -m pip install typogrify
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
|
@ -75,9 +69,8 @@ automatically installed without any action on your part:
|
|||
broadcast signaling system
|
||||
* `unidecode <https://pypi.org/project/Unidecode/>`_, for ASCII
|
||||
transliterations of Unicode text
|
||||
* `six <https://pypi.org/project/six/>`_, for Python 2 and 3 compatibility
|
||||
utilities
|
||||
* `MarkupSafe <https://pypi.org/project/MarkupSafe/>`_, for a markup safe
|
||||
* `MarkupSafe <https://pypi.org/project/MarkupSafe/>`_, for a markup-safe
|
||||
string implementation
|
||||
* `python-dateutil <https://pypi.org/project/python-dateutil/>`_, to read
|
||||
the date metadata
|
||||
|
|
@ -85,10 +78,10 @@ automatically installed without any action on your part:
|
|||
Upgrading
|
||||
---------
|
||||
|
||||
If you installed a stable Pelican release via ``pip`` and wish to upgrade to
|
||||
If you installed a stable Pelican release via Pip_ and wish to upgrade to
|
||||
the latest stable release, you can do so by adding ``--upgrade``::
|
||||
|
||||
pip install --upgrade pelican
|
||||
python -m 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.
|
||||
|
|
@ -126,4 +119,5 @@ content)::
|
|||
The next step is to begin to adding content to the *content* folder that has
|
||||
been created for you.
|
||||
|
||||
.. _Pip: https://pip.pypa.io/
|
||||
.. _virtualenv: https://virtualenv.pypa.io/en/latest/
|
||||
|
|
|
|||
|
|
@ -44,17 +44,22 @@ HTML content and some metadata.
|
|||
|
||||
Take a look at the Markdown reader::
|
||||
|
||||
from pelican.readers import BaseReader
|
||||
from pelican.utils import pelican_open
|
||||
from markdown import Markdown
|
||||
|
||||
class MarkdownReader(BaseReader):
|
||||
enabled = bool(Markdown)
|
||||
enabled = True
|
||||
|
||||
def read(self, source_path):
|
||||
"""Parse content and metadata of markdown files"""
|
||||
text = pelican_open(source_path)
|
||||
md_extensions = {'markdown.extensions.meta': {},
|
||||
'markdown.extensions.codehilite': {}}
|
||||
md = Markdown(extensions=md_extensions.keys(),
|
||||
extension_configs=md_extensions)
|
||||
content = md.convert(text)
|
||||
|
||||
with pelican_open(source_path) as text:
|
||||
md_extensions = {'markdown.extensions.meta': {},
|
||||
'markdown.extensions.codehilite': {}}
|
||||
md = Markdown(extensions=md_extensions.keys(),
|
||||
extension_configs=md_extensions)
|
||||
content = md.convert(text)
|
||||
|
||||
metadata = {}
|
||||
for name, value in md.Meta.items():
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ How to use plugins
|
|||
Starting with version 4.5, Pelican moved to a new plugin structure utilizing
|
||||
namespace packages that can be easily installed via Pip_. Plugins supporting
|
||||
this structure will install under the namespace package ``pelican.plugins`` and
|
||||
can be automatically discovered by Pelican. To see a list of plugins that are
|
||||
active in your environment, run::
|
||||
can be automatically discovered by Pelican. To see a list of Pip-installed
|
||||
namespace plugins that are active in your environment, run::
|
||||
|
||||
pelican-plugins
|
||||
|
||||
|
|
@ -70,8 +70,8 @@ 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 subsequent
|
||||
section.
|
||||
subscribe to those signals. The list of available signals is documented in a
|
||||
subsequent section.
|
||||
|
||||
The only rule to follow for plugins is to define a ``register`` callable, in
|
||||
which you map the signals to your plugin logic. Let's take a simple example::
|
||||
|
|
@ -94,6 +94,10 @@ which you map the signals to your plugin logic. Let's take a simple example::
|
|||
your ``register`` callable or they will be garbage-collected before the
|
||||
signal is emitted.
|
||||
|
||||
If multiple plugins connect to the same signal, there is no way to guarantee or
|
||||
control in which order the plugins will be executed. This is a limitation
|
||||
inherited from Blinker_, the dependency Pelican uses to implement signals.
|
||||
|
||||
Namespace plugin structure
|
||||
--------------------------
|
||||
|
||||
|
|
@ -272,3 +276,4 @@ Adding a new generator is also really easy. You might want to have a look at
|
|||
|
||||
.. _Pip: https://pip.pypa.io/
|
||||
.. _pelican-plugins bug #314: https://github.com/getpelican/pelican-plugins/issues/314
|
||||
.. _Blinker: https://pythonhosted.org/blinker/
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ in a wide range of environments. The downside is that it must be installed
|
|||
separately. Use the following command to install Invoke, prefixing with
|
||||
``sudo`` if your environment requires it::
|
||||
|
||||
pip install invoke
|
||||
python -m pip install invoke
|
||||
|
||||
Take a moment to open the ``tasks.py`` file that was generated in your project
|
||||
root. You will see a number of commands, any one of which can be renamed,
|
||||
|
|
@ -139,7 +139,7 @@ http://localhost:8000/::
|
|||
invoke serve
|
||||
|
||||
To serve the generated site with automatic browser reloading every time a
|
||||
change is detected, first ``pip install livereload``, then use the
|
||||
change is detected, first ``python -m pip install livereload``, then use the
|
||||
following command::
|
||||
|
||||
invoke livereload
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ Installation
|
|||
------------
|
||||
|
||||
Install Pelican (and optionally Markdown if you intend to use it) on Python
|
||||
2.7.x or Python 3.5+ by running the following command in your preferred
|
||||
terminal, prefixing with ``sudo`` if permissions warrant::
|
||||
3.6+ by running the following command in your preferred terminal, prefixing
|
||||
with ``sudo`` if permissions warrant::
|
||||
|
||||
pip install pelican[Markdown]
|
||||
python -m pip install "pelican[markdown]"
|
||||
|
||||
Create a project
|
||||
----------------
|
||||
|
|
|
|||
|
|
@ -9,6 +9,12 @@ line::
|
|||
If you used the ``pelican-quickstart`` command, your primary settings file will
|
||||
be named ``pelicanconf.py`` by default.
|
||||
|
||||
You can also specify extra settings via ``-e`` / ``--extra-settings`` option
|
||||
flags, which will override default settings as well as any defined within
|
||||
settings files::
|
||||
|
||||
pelican content -e DELETE_OUTPUT_DIRECTORY=true
|
||||
|
||||
.. note::
|
||||
|
||||
When experimenting with different settings (especially the metadata ones)
|
||||
|
|
@ -270,8 +276,8 @@ Basic settings
|
|||
|
||||
If set to True, several typographical improvements will be incorporated into
|
||||
the generated HTML via the `Typogrify
|
||||
<https://pypi.python.org/pypi/typogrify>`_ library, which can be installed
|
||||
via: ``pip install typogrify``
|
||||
<https://pypi.org/project/typogrify/>`_ library, which can be installed
|
||||
via: ``python -m pip install typogrify``
|
||||
|
||||
.. data:: TYPOGRIFY_IGNORE_TAGS = []
|
||||
|
||||
|
|
@ -297,10 +303,10 @@ Basic settings
|
|||
does not otherwise specify a summary. Setting to ``None`` will cause the
|
||||
summary to be a copy of the original content.
|
||||
|
||||
.. data:: SUMMARY_END_MARKER = '…'
|
||||
.. data:: SUMMARY_END_SUFFIX = '…'
|
||||
|
||||
When creating a short summary of an article and the result was truncated to
|
||||
match the required word length, this will be used as the truncation marker.
|
||||
match the required word length, this will be used as the truncation suffix.
|
||||
|
||||
.. data:: WITH_FUTURE_DATES = True
|
||||
|
||||
|
|
@ -770,7 +776,7 @@ Template pages
|
|||
.. data:: TEMPLATE_PAGES = None
|
||||
|
||||
A mapping containing template pages that will be rendered with the blog
|
||||
entries. See :ref:`template_pages`.
|
||||
entries.
|
||||
|
||||
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
|
||||
|
|
@ -1061,6 +1067,11 @@ as follows::
|
|||
)
|
||||
|
||||
|
||||
If you want a pattern to apply to the last page in the list, use ``-1``
|
||||
as the ``minimum_page`` value::
|
||||
|
||||
(-1, '{base_name}/last/', '{base_name}/last/index.html'),
|
||||
|
||||
Translations
|
||||
============
|
||||
|
||||
|
|
@ -1123,10 +1134,11 @@ Ordering content
|
|||
|
||||
Defines how the articles (``articles_page.object_list`` in the template) are
|
||||
sorted. Valid options are: metadata as a string (use ``reversed-`` prefix
|
||||
the reverse the sort order), special option ``'basename'`` which will use
|
||||
the basename of the file (without path) or a custom function to extract the
|
||||
sorting key from articles. The default value, ``'reversed-date'``, will sort
|
||||
articles by date in reverse order (i.e. newest article comes first).
|
||||
to reverse the sort order), special option ``'basename'`` which will use
|
||||
the basename of the file (without path), or a custom function to extract the
|
||||
sorting key from articles. Using a value of ``'date'`` will sort articles in
|
||||
chronological order, while the default value, ``'reversed-date'``, will sort
|
||||
articles by date in reverse order (i.e., newest article comes first).
|
||||
|
||||
.. data:: PAGE_ORDER_BY = 'basename'
|
||||
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ from pelican.generators import (ArticlesGenerator, # noqa: I100
|
|||
PagesGenerator, SourceFileGenerator,
|
||||
StaticGenerator, TemplatePagesGenerator)
|
||||
from pelican.plugins import signals
|
||||
from pelican.plugins._utils import load_plugins
|
||||
from pelican.plugins._utils import get_plugin_name, load_plugins
|
||||
from pelican.readers import Readers
|
||||
from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer
|
||||
from pelican.settings import read_settings
|
||||
from pelican.settings import coerce_overrides, read_settings
|
||||
from pelican.utils import (FileSystemWatcher, clean_output_dir, maybe_pluralize)
|
||||
from pelican.writers import Writer
|
||||
|
||||
|
|
@ -65,14 +65,18 @@ class Pelican:
|
|||
sys.path.insert(0, '')
|
||||
|
||||
def init_plugins(self):
|
||||
self.plugins = load_plugins(self.settings)
|
||||
for plugin in self.plugins:
|
||||
logger.debug('Registering plugin `%s`', plugin.__name__)
|
||||
self.plugins = []
|
||||
for plugin in load_plugins(self.settings):
|
||||
name = get_plugin_name(plugin)
|
||||
logger.debug('Registering plugin `%s`', name)
|
||||
try:
|
||||
plugin.register()
|
||||
self.plugins.append(plugin)
|
||||
except Exception as e:
|
||||
logger.error('Cannot register plugin `%s`\n%s',
|
||||
plugin.__name__, e)
|
||||
name, e)
|
||||
|
||||
self.settings['PLUGINS'] = [get_plugin_name(p) for p in self.plugins]
|
||||
|
||||
def run(self):
|
||||
"""Run the generators and return"""
|
||||
|
|
@ -93,7 +97,7 @@ class Pelican:
|
|||
path=self.path,
|
||||
theme=self.theme,
|
||||
output_path=self.output_path,
|
||||
) for cls in self.get_generator_classes()
|
||||
) for cls in self._get_generator_classes()
|
||||
]
|
||||
|
||||
# Delete the output directory if (1) the appropriate setting is True
|
||||
|
|
@ -114,7 +118,7 @@ class Pelican:
|
|||
|
||||
signals.all_generators_finalized.send(generators)
|
||||
|
||||
writer = self.get_writer()
|
||||
writer = self._get_writer()
|
||||
|
||||
for p in generators:
|
||||
if hasattr(p, 'generate_output'):
|
||||
|
|
@ -168,46 +172,57 @@ class Pelican:
|
|||
pluralized_draft_pages,
|
||||
time.time() - start_time))
|
||||
|
||||
def get_generator_classes(self):
|
||||
generators = [ArticlesGenerator, PagesGenerator]
|
||||
def _get_generator_classes(self):
|
||||
discovered_generators = [
|
||||
(ArticlesGenerator, "internal"),
|
||||
(PagesGenerator, "internal")
|
||||
]
|
||||
|
||||
if self.settings['TEMPLATE_PAGES']:
|
||||
generators.append(TemplatePagesGenerator)
|
||||
if self.settings['OUTPUT_SOURCES']:
|
||||
generators.append(SourceFileGenerator)
|
||||
if self.settings["TEMPLATE_PAGES"]:
|
||||
discovered_generators.append((TemplatePagesGenerator, "internal"))
|
||||
|
||||
for pair in signals.get_generators.send(self):
|
||||
(funct, value) = pair
|
||||
if self.settings["OUTPUT_SOURCES"]:
|
||||
discovered_generators.append((SourceFileGenerator, "internal"))
|
||||
|
||||
if not isinstance(value, Iterable):
|
||||
value = (value, )
|
||||
|
||||
for v in value:
|
||||
if isinstance(v, type):
|
||||
logger.debug('Found generator: %s', v)
|
||||
generators.append(v)
|
||||
for receiver, values in signals.get_generators.send(self):
|
||||
if not isinstance(values, Iterable):
|
||||
values = (values,)
|
||||
for generator in values:
|
||||
if generator is None:
|
||||
continue # plugin did not return a generator
|
||||
discovered_generators.append((generator, receiver.__module__))
|
||||
|
||||
# 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)
|
||||
discovered_generators.append((StaticGenerator, "internal"))
|
||||
|
||||
generators = []
|
||||
|
||||
for generator, origin in discovered_generators:
|
||||
if not isinstance(generator, type):
|
||||
logger.error("Generator %s (%s) cannot be loaded", generator, origin)
|
||||
continue
|
||||
|
||||
logger.debug("Found generator: %s (%s)", generator.__name__, origin)
|
||||
generators.append(generator)
|
||||
|
||||
return generators
|
||||
|
||||
def get_writer(self):
|
||||
writers = [w for (_, w) in signals.get_writer.send(self)
|
||||
if isinstance(w, type)]
|
||||
writers_found = len(writers)
|
||||
if writers_found == 0:
|
||||
def _get_writer(self):
|
||||
writers = [w for _, w in signals.get_writer.send(self) if isinstance(w, type)]
|
||||
num_writers = len(writers)
|
||||
|
||||
if num_writers == 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)
|
||||
|
||||
if num_writers > 1:
|
||||
logger.warning("%s writers found, using only first one", num_writers)
|
||||
|
||||
writer = writers[0]
|
||||
|
||||
logger.debug("Found writer: %s", writer)
|
||||
return writer(self.output_path, settings=self.settings)
|
||||
|
||||
|
||||
class PrintSettings(argparse.Action):
|
||||
|
|
@ -236,6 +251,18 @@ class PrintSettings(argparse.Action):
|
|||
parser.exit()
|
||||
|
||||
|
||||
class ParseDict(argparse.Action):
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
d = {}
|
||||
if values:
|
||||
for item in values:
|
||||
split_items = item.split("=", 1)
|
||||
key = split_items[0].strip()
|
||||
value = split_items[1].strip()
|
||||
d[key] = value
|
||||
setattr(namespace, self.dest, d)
|
||||
|
||||
|
||||
def parse_arguments(argv=None):
|
||||
parser = argparse.ArgumentParser(
|
||||
description='A tool to generate a static blog, '
|
||||
|
|
@ -329,6 +356,16 @@ def parse_arguments(argv=None):
|
|||
help='IP to bind to when serving files via HTTP '
|
||||
'(default: 127.0.0.1)')
|
||||
|
||||
parser.add_argument('-e', '--extra-settings', dest='overrides',
|
||||
help='Specify one or more SETTING=VALUE pairs to '
|
||||
'override settings. If VALUE contains spaces, '
|
||||
'add quotes: SETTING="VALUE". Values other than '
|
||||
'integers and strings can be specified via JSON '
|
||||
'notation. (e.g., SETTING=none)',
|
||||
nargs='*',
|
||||
action=ParseDict
|
||||
)
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
if args.port is not None and not args.listen:
|
||||
|
|
@ -364,6 +401,7 @@ def get_config(args):
|
|||
if args.bind is not None:
|
||||
config['BIND'] = args.bind
|
||||
config['DEBUG'] = args.verbosity == logging.DEBUG
|
||||
config.update(coerce_overrides(args.overrides))
|
||||
|
||||
return config
|
||||
|
||||
|
|
@ -441,7 +479,7 @@ def listen(server, port, output, excqueue=None):
|
|||
return
|
||||
|
||||
try:
|
||||
print("\nServing site at: {}:{} - Tap CTRL-C to stop".format(
|
||||
print("\nServing site at: http://{}:{} - Tap CTRL-C to stop".format(
|
||||
server, port))
|
||||
httpd.serve_forever()
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import locale
|
|||
import logging
|
||||
import os
|
||||
import re
|
||||
from urllib.parse import urljoin, urlparse, urlunparse
|
||||
from html import unescape
|
||||
from urllib.parse import unquote, urljoin, urlparse, urlunparse
|
||||
|
||||
import pytz
|
||||
|
||||
|
|
@ -250,38 +251,55 @@ class Content:
|
|||
|
||||
# XXX Put this in a different location.
|
||||
if what in {'filename', 'static', 'attach'}:
|
||||
if path.startswith('/'):
|
||||
path = path[1:]
|
||||
def _get_linked_content(key, url):
|
||||
nonlocal value
|
||||
|
||||
def _find_path(path):
|
||||
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)
|
||||
)
|
||||
return self._context[key].get(path, None)
|
||||
|
||||
# try path
|
||||
result = _find_path(url.path)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
# try unquoted path
|
||||
result = _find_path(unquote(url.path))
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
# try html unescaped url
|
||||
unescaped_url = urlparse(unescape(url.geturl()))
|
||||
result = _find_path(unescaped_url.path)
|
||||
if result is not None:
|
||||
value = unescaped_url
|
||||
return result
|
||||
|
||||
# check if a static file is linked with {filename}
|
||||
if what == 'filename' and key == 'generated_content':
|
||||
linked_content = _get_linked_content('static_content', value)
|
||||
if linked_content:
|
||||
logger.warning(
|
||||
'{filename} used for linking to static'
|
||||
' content %s in %s. Use {static} instead',
|
||||
value.path,
|
||||
self.get_relative_source_path())
|
||||
return linked_content
|
||||
|
||||
return None
|
||||
|
||||
if what == 'filename':
|
||||
key = 'generated_content'
|
||||
else:
|
||||
# relative to the source path of this content
|
||||
path = self.get_relative_source_path(
|
||||
os.path.join(self.relative_dir, path)
|
||||
)
|
||||
key = 'static_content'
|
||||
|
||||
key = 'static_content' if what in ('static', 'attach')\
|
||||
else 'generated_content'
|
||||
|
||||
def _get_linked_content(key, path):
|
||||
try:
|
||||
return self._context[key][path]
|
||||
except KeyError:
|
||||
try:
|
||||
# Markdown escapes spaces, try unescaping
|
||||
return self._context[key][path.replace('%20', ' ')]
|
||||
except KeyError:
|
||||
if what == 'filename' and key == 'generated_content':
|
||||
key = 'static_content'
|
||||
linked_content = _get_linked_content(key, path)
|
||||
if linked_content:
|
||||
logger.warning(
|
||||
'{filename} used for linking to static'
|
||||
' content %s in %s. Use {static} instead',
|
||||
path,
|
||||
self.get_relative_source_path())
|
||||
return linked_content
|
||||
return None
|
||||
|
||||
linked_content = _get_linked_content(key, path)
|
||||
linked_content = _get_linked_content(key, value)
|
||||
if linked_content:
|
||||
if what == 'attach':
|
||||
linked_content.attach_to(self)
|
||||
|
|
@ -392,7 +410,7 @@ class Content:
|
|||
|
||||
return truncate_html_words(self.content,
|
||||
self.settings['SUMMARY_MAX_LENGTH'],
|
||||
self.settings['SUMMARY_END_MARKER'])
|
||||
self.settings['SUMMARY_END_SUFFIX'])
|
||||
|
||||
@property
|
||||
def summary(self):
|
||||
|
|
|
|||
|
|
@ -118,8 +118,13 @@ class Page:
|
|||
|
||||
# find the last matching pagination rule
|
||||
for p in self.settings['PAGINATION_PATTERNS']:
|
||||
if p.min_page <= self.number:
|
||||
rule = p
|
||||
if p.min_page == -1:
|
||||
if not self.has_next():
|
||||
rule = p
|
||||
break
|
||||
else:
|
||||
if p.min_page <= self.number:
|
||||
rule = p
|
||||
|
||||
if not rule:
|
||||
return ''
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import importlib
|
||||
import importlib.machinery
|
||||
import importlib.util
|
||||
import inspect
|
||||
import logging
|
||||
import pkgutil
|
||||
import sys
|
||||
|
|
@ -40,6 +41,11 @@ def list_plugins(ns_pkg=None):
|
|||
|
||||
|
||||
def load_legacy_plugin(plugin, plugin_paths):
|
||||
if '.' in plugin:
|
||||
# it is in a package, try to resolve package first
|
||||
package, _, _ = plugin.rpartition('.')
|
||||
load_legacy_plugin(package, plugin_paths)
|
||||
|
||||
# Try to find plugin in PLUGIN_PATHS
|
||||
spec = importlib.machinery.PathFinder.find_spec(plugin, plugin_paths)
|
||||
if spec is None:
|
||||
|
|
@ -48,6 +54,9 @@ def load_legacy_plugin(plugin, plugin_paths):
|
|||
if spec is None:
|
||||
raise ImportError('Cannot import plugin `{}`'.format(plugin))
|
||||
else:
|
||||
# Avoid loading the same plugin twice
|
||||
if spec.name in sys.modules:
|
||||
return sys.modules[spec.name]
|
||||
# create module object from spec
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
# place it into sys.modules cache
|
||||
|
|
@ -99,3 +108,18 @@ def load_plugins(settings):
|
|||
plugins = list(namespace_plugins.values())
|
||||
|
||||
return plugins
|
||||
|
||||
|
||||
def get_plugin_name(plugin):
|
||||
"""
|
||||
Plugins can be passed as module objects, however this breaks caching as
|
||||
module objects cannot be pickled. To work around this, all plugins are
|
||||
stringified post-initialization.
|
||||
"""
|
||||
if inspect.isclass(plugin):
|
||||
return plugin.__qualname__
|
||||
|
||||
if inspect.ismodule(plugin):
|
||||
return plugin.__name__
|
||||
|
||||
return type(plugin).__qualname__
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ class RstReader(BaseReader):
|
|||
if element.tagname == 'field': # custom fields (e.g. summary)
|
||||
name_elem, body_elem = element.children
|
||||
name = name_elem.astext()
|
||||
if name in formatted_fields:
|
||||
if name.lower() in formatted_fields:
|
||||
value = render_node_to_html(
|
||||
document, body_elem,
|
||||
self.field_body_translator_class)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import copy
|
||||
import importlib.util
|
||||
import inspect
|
||||
import json
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
|
|
@ -135,7 +136,7 @@ DEFAULT_CONFIG = {
|
|||
'TYPOGRIFY': False,
|
||||
'TYPOGRIFY_IGNORE_TAGS': [],
|
||||
'TYPOGRIFY_DASHES': 'default',
|
||||
'SUMMARY_END_MARKER': '…',
|
||||
'SUMMARY_END_SUFFIX': '…',
|
||||
'SUMMARY_MAX_LENGTH': 50,
|
||||
'PLUGIN_PATHS': [],
|
||||
'PLUGINS': None,
|
||||
|
|
@ -658,3 +659,25 @@ def configure_settings(settings):
|
|||
continue # setting not specified, nothing to do
|
||||
|
||||
return settings
|
||||
|
||||
|
||||
def coerce_overrides(overrides):
|
||||
if overrides is None:
|
||||
return {}
|
||||
coerced = {}
|
||||
types_to_cast = {int, str, bool}
|
||||
for k, v in overrides.items():
|
||||
if k not in DEFAULT_CONFIG:
|
||||
logger.warning('Override for unknown setting %s, ignoring', k)
|
||||
continue
|
||||
setting_type = type(DEFAULT_CONFIG[k])
|
||||
if setting_type not in types_to_cast:
|
||||
coerced[k] = json.loads(v)
|
||||
else:
|
||||
try:
|
||||
coerced[k] = setting_type(v)
|
||||
except ValueError:
|
||||
logger.debug('ValueError for %s override with %s, try to '
|
||||
'load as json', k, v)
|
||||
coerced[k] = json.loads(v)
|
||||
return coerced
|
||||
|
|
|
|||
4
pelican/signals.py
Normal file
4
pelican/signals.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
raise ImportError(
|
||||
'Importing from `pelican.signals` is deprecated. '
|
||||
'Use `from pelican import signals` or `import pelican.plugins.signals` instead.'
|
||||
)
|
||||
16
pelican/tests/content/article_with_capitalized_metadata.rst
vendored
Normal file
16
pelican/tests/content/article_with_capitalized_metadata.rst
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
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
|
||||
:CUSTOM_FORMATTED_FIELD:
|
||||
Multi-line metadata should also be supported
|
||||
as well as *inline markup* and stuff to "typogrify"...
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
from .submodule import noop # noqa: F401
|
||||
|
||||
NAME = 'normal plugin'
|
||||
|
||||
|
||||
def register():
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
def register():
|
||||
pass
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
def register():
|
||||
pass
|
||||
|
|
@ -81,7 +81,7 @@
|
|||
<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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -220,7 +220,7 @@ YEAH !</p>
|
|||
<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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -168,4 +168,4 @@
|
|||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -183,4 +183,4 @@ YEAH !</p>
|
|||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
@ -133,4 +133,4 @@ pelican.conf, it will …</p></div>
|
|||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -94,7 +94,7 @@
|
|||
<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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -19,7 +19,7 @@ YEAH !</p>
|
|||
<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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -21,7 +21,7 @@ YEAH !</p>
|
|||
<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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -6,7 +6,7 @@
|
|||
<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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
|
|||
|
|
@ -168,4 +168,4 @@
|
|||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -183,4 +183,4 @@ YEAH !</p>
|
|||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
@ -133,4 +133,4 @@ pelican.conf, it will …</p></div>
|
|||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -168,4 +168,4 @@
|
|||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -183,4 +183,4 @@ YEAH !</p>
|
|||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<a class="reference external" href="../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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
@ -133,4 +133,4 @@ pelican.conf, it will …</p></div>
|
|||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -94,7 +94,7 @@
|
|||
<a class="reference external" href="../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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -19,7 +19,7 @@ YEAH !</p>
|
|||
<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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -21,7 +21,7 @@ YEAH !</p>
|
|||
<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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -6,7 +6,7 @@
|
|||
<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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
|
|||
|
|
@ -168,4 +168,4 @@
|
|||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -183,4 +183,4 @@ YEAH !</p>
|
|||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<a class="reference external" href="./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></span><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>
|
||||
<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal">1</span></pre></div></td><td class="code"><div class="highlight"><pre><span></span><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">
|
||||
|
|
@ -133,4 +133,4 @@ pelican.conf, it will …</p></div>
|
|||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -30,6 +30,9 @@ class TestBase(LoggedTestCase):
|
|||
'content': TEST_CONTENT,
|
||||
'context': {
|
||||
'localsiteurl': '',
|
||||
'generated_content': {},
|
||||
'static_content': {},
|
||||
'static_links': set()
|
||||
},
|
||||
'metadata': {
|
||||
'summary': TEST_SUMMARY,
|
||||
|
|
@ -110,14 +113,14 @@ class TestPage(TestBase):
|
|||
page = Page(**page_kwargs)
|
||||
self.assertEqual(page.summary, '')
|
||||
|
||||
def test_summary_end_marker(self):
|
||||
# If a :SUMMARY_END_MARKER: is set, and there is no other summary,
|
||||
def test_summary_end_suffix(self):
|
||||
# If a :SUMMARY_END_SUFFIX: is set, and there is no other summary,
|
||||
# generated summary should contain the specified marker at the end.
|
||||
page_kwargs = self._copy_page_kwargs()
|
||||
settings = get_settings()
|
||||
page_kwargs['settings'] = settings
|
||||
del page_kwargs['metadata']['summary']
|
||||
settings['SUMMARY_END_MARKER'] = 'test_marker'
|
||||
settings['SUMMARY_END_SUFFIX'] = 'test_marker'
|
||||
settings['SUMMARY_MAX_LENGTH'] = 10
|
||||
page = Page(**page_kwargs)
|
||||
self.assertEqual(page.summary, truncate_html_words(TEST_CONTENT, 10,
|
||||
|
|
@ -519,6 +522,60 @@ class TestPage(TestBase):
|
|||
'<img src="http://static.cool.site/images/poster.jpg"/>'
|
||||
)
|
||||
|
||||
def test_intrasite_link_escape(self):
|
||||
article = type(
|
||||
'_DummyArticle', (object,), {'url': 'article-spaces.html'})
|
||||
asset = type(
|
||||
'_DummyAsset', (object,), {'url': 'name@example.com'})
|
||||
|
||||
args = self.page_kwargs.copy()
|
||||
args['settings'] = get_settings()
|
||||
args['source_path'] = 'content'
|
||||
args['context']['generated_content'] = {'article spaces.rst': article}
|
||||
args['context']['static_content'] = {'name@example.com': asset}
|
||||
|
||||
expected_output = (
|
||||
'A simple test with a '
|
||||
'<a href="http://notmyidea.org/article-spaces.html#anchor">link</a> '
|
||||
'<a href="http://notmyidea.org/name@example.com#anchor">file</a>'
|
||||
)
|
||||
|
||||
# not escaped
|
||||
args['content'] = (
|
||||
'A simple test with a '
|
||||
'<a href="{filename}article spaces.rst#anchor">link</a> '
|
||||
'<a href="{static}name@example.com#anchor">file</a>'
|
||||
)
|
||||
content = Page(**args).get_content('http://notmyidea.org')
|
||||
self.assertEqual(content, expected_output)
|
||||
|
||||
# html escaped
|
||||
args['content'] = (
|
||||
'A simple test with a '
|
||||
'<a href="{filename}article spaces.rst#anchor">link</a> '
|
||||
'<a href="{static}name@example.com#anchor">file</a>'
|
||||
)
|
||||
content = Page(**args).get_content('http://notmyidea.org')
|
||||
self.assertEqual(content, expected_output)
|
||||
|
||||
# url escaped
|
||||
args['content'] = (
|
||||
'A simple test with a '
|
||||
'<a href="{filename}article%20spaces.rst#anchor">link</a> '
|
||||
'<a href="{static}name%40example.com#anchor">file</a>'
|
||||
)
|
||||
content = Page(**args).get_content('http://notmyidea.org')
|
||||
self.assertEqual(content, expected_output)
|
||||
|
||||
# html and url escaped
|
||||
args['content'] = (
|
||||
'A simple test with a '
|
||||
'<a href="{filename}article%20spaces.rst#anchor">link</a> '
|
||||
'<a href="{static}name@example.com#anchor">file</a>'
|
||||
)
|
||||
content = Page(**args).get_content('http://notmyidea.org')
|
||||
self.assertEqual(content, expected_output)
|
||||
|
||||
def test_intrasite_link_markdown_spaces(self):
|
||||
cls_name = '_DummyArticle'
|
||||
article = type(cls_name, (object,), {'url': 'article-spaces.html'})
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
|||
['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', 'yeah', 'article'],
|
||||
['This is a super article !', 'published', 'Default', 'article'],
|
||||
['Article with an inline SVG', 'published', 'Default', 'article'],
|
||||
['This is an article with category !', 'published', 'yeah',
|
||||
|
|
@ -590,6 +591,7 @@ class TestArticlesGenerator(unittest.TestCase):
|
|||
'This is a super article !',
|
||||
'This is a super article !',
|
||||
'This is a super article !',
|
||||
'This is a super article !',
|
||||
'This is an article with category !',
|
||||
('This is an article with multiple authors in lastname, '
|
||||
'firstname format!'),
|
||||
|
|
|
|||
|
|
@ -76,3 +76,29 @@ class TestPage(unittest.TestCase):
|
|||
page2 = paginator.page(2)
|
||||
self.assertEqual(page2.save_as, 'blog/2/index.html')
|
||||
self.assertEqual(page2.url, '//blog.my.site/2/')
|
||||
|
||||
def test_custom_pagination_pattern_last_page(self):
|
||||
from pelican.paginator import PaginationRule
|
||||
settings = get_settings()
|
||||
settings['PAGINATION_PATTERNS'] = [PaginationRule(*r) for r in [
|
||||
(1, '/{url}1/', '{base_name}/1/index.html'),
|
||||
(2, '/{url}{number}/', '{base_name}/{number}/index.html'),
|
||||
(-1, '/{url}', '{base_name}/index.html'),
|
||||
]]
|
||||
|
||||
self.page_kwargs['metadata']['author'] = Author('Blogger', settings)
|
||||
object_list = [Article(**self.page_kwargs),
|
||||
Article(**self.page_kwargs),
|
||||
Article(**self.page_kwargs)]
|
||||
paginator = Paginator('blog/index.html', '//blog.my.site/',
|
||||
object_list, settings, 1)
|
||||
# The URL *has to* stay absolute (with // in the front), so verify that
|
||||
page1 = paginator.page(1)
|
||||
self.assertEqual(page1.save_as, 'blog/1/index.html')
|
||||
self.assertEqual(page1.url, '//blog.my.site/1/')
|
||||
page2 = paginator.page(2)
|
||||
self.assertEqual(page2.save_as, 'blog/2/index.html')
|
||||
self.assertEqual(page2.url, '//blog.my.site/2/')
|
||||
page3 = paginator.page(3)
|
||||
self.assertEqual(page3.save_as, 'blog/index.html')
|
||||
self.assertEqual(page3.url, '//blog.my.site/')
|
||||
|
|
|
|||
|
|
@ -84,14 +84,14 @@ class TestPelican(LoggedTestCase):
|
|||
# have their output paths overridden by the {attach} link syntax.
|
||||
|
||||
pelican = Pelican(settings=read_settings(path=None))
|
||||
generator_classes = pelican.get_generator_classes()
|
||||
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, Sequence,
|
||||
"get_generator_classes() must return a Sequence to preserve order")
|
||||
"_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
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import os
|
||||
from contextlib import contextmanager
|
||||
|
||||
from pelican.plugins._utils import get_namespace_plugins, load_plugins
|
||||
import pelican.tests.dummy_plugins.normal_plugin.normal_plugin as normal_plugin
|
||||
from pelican.plugins._utils import (get_namespace_plugins, get_plugin_name,
|
||||
load_plugins)
|
||||
from pelican.tests.support import unittest
|
||||
|
||||
|
||||
|
|
@ -81,9 +83,7 @@ class PluginTest(unittest.TestCase):
|
|||
|
||||
def test_load_plugins(self):
|
||||
def get_plugin_names(plugins):
|
||||
return {
|
||||
plugin.NAME if hasattr(plugin, 'NAME') else plugin.__name__
|
||||
for plugin in plugins}
|
||||
return {get_plugin_name(p) for p in plugins}
|
||||
|
||||
# existing namespace plugins
|
||||
existing_ns_plugins = load_plugins({})
|
||||
|
|
@ -93,7 +93,7 @@ class PluginTest(unittest.TestCase):
|
|||
plugins = load_plugins({})
|
||||
self.assertEqual(len(plugins), len(existing_ns_plugins)+1, plugins)
|
||||
self.assertEqual(
|
||||
{'namespace plugin'} | get_plugin_names(existing_ns_plugins),
|
||||
{'pelican.plugins.ns_plugin'} | get_plugin_names(existing_ns_plugins),
|
||||
get_plugin_names(plugins))
|
||||
|
||||
# disable namespace plugins with `PLUGINS = []`
|
||||
|
|
@ -113,9 +113,35 @@ class PluginTest(unittest.TestCase):
|
|||
plugins = load_plugins(SETTINGS)
|
||||
self.assertEqual(len(plugins), 1, plugins)
|
||||
self.assertEqual(
|
||||
{'normal plugin'},
|
||||
{'normal_plugin'},
|
||||
get_plugin_names(plugins))
|
||||
|
||||
# normal submodule/subpackage plugins
|
||||
SETTINGS = {
|
||||
'PLUGINS': [
|
||||
'normal_submodule_plugin.subplugin',
|
||||
'normal_submodule_plugin.subpackage.subpackage',
|
||||
],
|
||||
'PLUGIN_PATHS': [self._NORMAL_PLUGIN_FOLDER]
|
||||
}
|
||||
plugins = load_plugins(SETTINGS)
|
||||
self.assertEqual(len(plugins), 2, plugins)
|
||||
self.assertEqual(
|
||||
{'normal_submodule_plugin.subplugin',
|
||||
'normal_submodule_plugin.subpackage.subpackage'},
|
||||
get_plugin_names(plugins))
|
||||
|
||||
# ensure normal plugins are loaded only once
|
||||
SETTINGS = {
|
||||
'PLUGINS': ['normal_plugin'],
|
||||
'PLUGIN_PATHS': [self._NORMAL_PLUGIN_FOLDER],
|
||||
}
|
||||
plugins = load_plugins(SETTINGS)
|
||||
for plugin in load_plugins(SETTINGS):
|
||||
# The second load_plugins() should return the same plugin
|
||||
# objects as the first one
|
||||
self.assertIn(plugin, plugins)
|
||||
|
||||
# namespace plugin short
|
||||
SETTINGS = {
|
||||
'PLUGINS': ['ns_plugin']
|
||||
|
|
@ -123,7 +149,7 @@ class PluginTest(unittest.TestCase):
|
|||
plugins = load_plugins(SETTINGS)
|
||||
self.assertEqual(len(plugins), 1, plugins)
|
||||
self.assertEqual(
|
||||
{'namespace plugin'},
|
||||
{'pelican.plugins.ns_plugin'},
|
||||
get_plugin_names(plugins))
|
||||
|
||||
# namespace plugin long
|
||||
|
|
@ -133,7 +159,7 @@ class PluginTest(unittest.TestCase):
|
|||
plugins = load_plugins(SETTINGS)
|
||||
self.assertEqual(len(plugins), 1, plugins)
|
||||
self.assertEqual(
|
||||
{'namespace plugin'},
|
||||
{'pelican.plugins.ns_plugin'},
|
||||
get_plugin_names(plugins))
|
||||
|
||||
# normal and namespace plugin
|
||||
|
|
@ -144,5 +170,22 @@ class PluginTest(unittest.TestCase):
|
|||
plugins = load_plugins(SETTINGS)
|
||||
self.assertEqual(len(plugins), 2, plugins)
|
||||
self.assertEqual(
|
||||
{'normal plugin', 'namespace plugin'},
|
||||
{'normal_plugin', 'pelican.plugins.ns_plugin'},
|
||||
get_plugin_names(plugins))
|
||||
|
||||
def test_get_plugin_name(self):
|
||||
self.assertEqual(
|
||||
get_plugin_name(normal_plugin),
|
||||
'pelican.tests.dummy_plugins.normal_plugin.normal_plugin',
|
||||
)
|
||||
|
||||
class NoopPlugin:
|
||||
def register(self):
|
||||
pass
|
||||
|
||||
self.assertEqual(
|
||||
get_plugin_name(NoopPlugin),
|
||||
'PluginTest.test_get_plugin_name.<locals>.NoopPlugin')
|
||||
self.assertEqual(
|
||||
get_plugin_name(NoopPlugin()),
|
||||
'PluginTest.test_get_plugin_name.<locals>.NoopPlugin')
|
||||
|
|
|
|||
|
|
@ -155,6 +155,24 @@ class RstReaderTest(ReaderTest):
|
|||
|
||||
self.assertDictHasSubset(page.metadata, expected)
|
||||
|
||||
def test_article_with_capitalized_metadata(self):
|
||||
page = self.read_file(path='article_with_capitalized_metadata.rst')
|
||||
expected = {
|
||||
'category': 'yeah',
|
||||
'author': 'Alexis Métaireau',
|
||||
'title': 'This is a super article !',
|
||||
'summary': '<p class="first last">Multi-line metadata should be'
|
||||
' supported\nas well as <strong>inline'
|
||||
' markup</strong> and stuff to "typogrify'
|
||||
'"...</p>\n',
|
||||
'date': SafeDatetime(2010, 12, 2, 10, 14),
|
||||
'modified': SafeDatetime(2010, 12, 2, 10, 20),
|
||||
'tags': ['foo', 'bar', 'foobar'],
|
||||
'custom_field': 'http://notmyidea.org',
|
||||
}
|
||||
|
||||
self.assertDictHasSubset(page.metadata, expected)
|
||||
|
||||
def test_article_with_filename_metadata(self):
|
||||
page = self.read_file(
|
||||
path='2012-11-29_rst_w_filename_meta#foo-bar.rst',
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ from sys import platform
|
|||
|
||||
from pelican.settings import (DEFAULT_CONFIG, DEFAULT_THEME,
|
||||
_printf_s_to_format_field,
|
||||
configure_settings, handle_deprecated_settings,
|
||||
read_settings)
|
||||
coerce_overrides, configure_settings,
|
||||
handle_deprecated_settings, read_settings)
|
||||
from pelican.tests.support import unittest
|
||||
|
||||
|
||||
|
|
@ -304,3 +304,18 @@ class TestSettingsConfiguration(unittest.TestCase):
|
|||
[(r'C\+\+', 'cpp')] +
|
||||
self.settings['SLUG_REGEX_SUBSTITUTIONS'])
|
||||
self.assertNotIn('SLUG_SUBSTITUTIONS', settings)
|
||||
|
||||
def test_coerce_overrides(self):
|
||||
overrides = coerce_overrides({
|
||||
'ARTICLE_EXCLUDES': '["testexcl"]',
|
||||
'READERS': '{"foo": "bar"}',
|
||||
'STATIC_EXCLUDE_SOURCES': 'true',
|
||||
'THEME_STATIC_DIR': 'theme',
|
||||
})
|
||||
expected = {
|
||||
'ARTICLE_EXCLUDES': ["testexcl"],
|
||||
'READERS': {"foo": "bar"},
|
||||
'STATIC_EXCLUDE_SOURCES': True,
|
||||
'THEME_STATIC_DIR': 'theme',
|
||||
}
|
||||
self.assertDictEqual(overrides, expected)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "base.html" %}
|
||||
{% block html_lang %}{{ page.lang }}{% endblock %}
|
||||
{% block title %}{{ page.title }}{% endblock %}
|
||||
{% block title %}{{ page.title|striptags }}{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
{% import 'translations.html' as translations with context %}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ _jinja_env = Environment(
|
|||
|
||||
|
||||
_GITHUB_PAGES_BRANCHES = {
|
||||
'personal': 'master',
|
||||
'personal': 'main',
|
||||
'project': 'gh-pages'
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,8 +69,11 @@ help:
|
|||
@echo ' make serve [PORT=8000] serve site at http://localhost:8000'
|
||||
@echo ' make serve-global [SERVER=0.0.0.0] serve (as root) to $(SERVER):80 '
|
||||
@echo ' make devserver [PORT=8000] serve and regenerate together '
|
||||
@echo ' make devserver-global regenerate and serve on 0.0.0.0 '
|
||||
{% if ssh %}
|
||||
@echo ' make ssh_upload upload the web site via SSH '
|
||||
@echo ' make rsync_upload upload the web site via rsync+ssh '
|
||||
{% endif %}
|
||||
{% if dropbox %}
|
||||
@echo ' make dropbox_upload upload the web site via Dropbox '
|
||||
{% endif %}
|
||||
|
|
@ -101,32 +104,16 @@ regenerate:
|
|||
"$(PELICAN)" -r "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
|
||||
|
||||
serve:
|
||||
ifdef PORT
|
||||
"$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) -p $(PORT)
|
||||
else
|
||||
"$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
|
||||
endif
|
||||
|
||||
serve-global:
|
||||
ifdef PORT
|
||||
"$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) -p $(PORT) -b $(SERVER)
|
||||
else
|
||||
"$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) -b $(SERVER)
|
||||
endif
|
||||
|
||||
devserver:
|
||||
ifdef PORT
|
||||
"$(PELICAN)" -lr "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) -p $(PORT)
|
||||
else
|
||||
"$(PELICAN)" -lr "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
|
||||
endif
|
||||
|
||||
devserver-global:
|
||||
ifdef PORT
|
||||
$(PELICAN) -lr $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) -p $(PORT) -b 0.0.0.0
|
||||
else
|
||||
$(PELICAN) -lr $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) -b 0.0.0.0
|
||||
endif
|
||||
|
||||
publish:
|
||||
"$(PELICAN)" "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(PUBLISHCONF)" $(PELICANOPTS)
|
||||
|
|
@ -139,7 +126,7 @@ ssh_upload: publish
|
|||
|
||||
{% set upload = upload + ["rsync_upload"] %}
|
||||
rsync_upload: publish
|
||||
rsync -e "ssh -p $(SSH_PORT)" -P -rvzc --cvs-exclude --delete "$(OUTPUTDIR)"/ "$(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)"
|
||||
rsync -e "ssh -p $(SSH_PORT)" -P -rvzc --include tags --cvs-exclude --delete "$(OUTPUTDIR)"/ "$(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)"
|
||||
|
||||
{% endif %}
|
||||
{% if dropbox %}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import shlex
|
||||
import shutil
|
||||
import sys
|
||||
import datetime
|
||||
|
||||
from invoke import task
|
||||
from invoke.main import program
|
||||
from invoke.util import cd
|
||||
from pelican import main as pelican_main
|
||||
from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer
|
||||
from pelican.settings import DEFAULT_CONFIG, get_settings_from_file
|
||||
|
||||
OPEN_BROWSER_ON_SERVE = True
|
||||
SETTINGS_FILE_BASE = 'pelicanconf.py'
|
||||
SETTINGS = {}
|
||||
SETTINGS.update(DEFAULT_CONFIG)
|
||||
|
|
@ -54,17 +58,17 @@ def clean(c):
|
|||
@task
|
||||
def build(c):
|
||||
"""Build local version of site"""
|
||||
c.run('pelican -s {settings_base}'.format(**CONFIG))
|
||||
pelican_run('-s {settings_base}'.format(**CONFIG))
|
||||
|
||||
@task
|
||||
def rebuild(c):
|
||||
"""`build` with the delete switch"""
|
||||
c.run('pelican -d -s {settings_base}'.format(**CONFIG))
|
||||
pelican_run('-d -s {settings_base}'.format(**CONFIG))
|
||||
|
||||
@task
|
||||
def regenerate(c):
|
||||
"""Automatically regenerate site upon file modification"""
|
||||
c.run('pelican -r -s {settings_base}'.format(**CONFIG))
|
||||
pelican_run('-r -s {settings_base}'.format(**CONFIG))
|
||||
|
||||
@task
|
||||
def serve(c):
|
||||
|
|
@ -78,6 +82,11 @@ def serve(c):
|
|||
(CONFIG['host'], CONFIG['port']),
|
||||
ComplexHTTPRequestHandler)
|
||||
|
||||
if OPEN_BROWSER_ON_SERVE:
|
||||
# Open site in default browser
|
||||
import webbrowser
|
||||
webbrowser.open("http://{host}:{port}".format(**CONFIG))
|
||||
|
||||
sys.stderr.write('Serving at {host}:{port} ...\n'.format(**CONFIG))
|
||||
server.serve_forever()
|
||||
|
||||
|
|
@ -90,29 +99,43 @@ def reserve(c):
|
|||
@task
|
||||
def preview(c):
|
||||
"""Build production version of site"""
|
||||
c.run('pelican -s {settings_publish}'.format(**CONFIG))
|
||||
pelican_run('-s {settings_publish}'.format(**CONFIG))
|
||||
|
||||
@task
|
||||
def livereload(c):
|
||||
"""Automatically reload browser tab upon file modification."""
|
||||
from livereload import Server
|
||||
build(c)
|
||||
|
||||
def cached_build():
|
||||
cmd = '-s {settings_base} -e CACHE_CONTENT=True LOAD_CONTENT_CACHE=True'
|
||||
pelican_run(cmd.format(**CONFIG))
|
||||
|
||||
cached_build()
|
||||
server = Server()
|
||||
# Watch the base settings file
|
||||
server.watch(CONFIG['settings_base'], lambda: build(c))
|
||||
# Watch content source files
|
||||
theme_path = SETTINGS['THEME']
|
||||
watched_globs = [
|
||||
CONFIG['settings_base'],
|
||||
'{}/templates/**/*.html'.format(theme_path),
|
||||
]
|
||||
|
||||
content_file_extensions = ['.md', '.rst']
|
||||
for extension in content_file_extensions:
|
||||
content_blob = '{0}/**/*{1}'.format(SETTINGS['PATH'], extension)
|
||||
server.watch(content_blob, lambda: build(c))
|
||||
# Watch the theme's templates and static assets
|
||||
theme_path = SETTINGS['THEME']
|
||||
server.watch('{}/templates/*.html'.format(theme_path), lambda: build(c))
|
||||
content_glob = '{0}/**/*{1}'.format(SETTINGS['PATH'], extension)
|
||||
watched_globs.append(content_glob)
|
||||
|
||||
static_file_extensions = ['.css', '.js']
|
||||
for extension in static_file_extensions:
|
||||
static_file = '{0}/static/**/*{1}'.format(theme_path, extension)
|
||||
server.watch(static_file, lambda: build(c))
|
||||
# Serve output path on configured host and port
|
||||
static_file_glob = '{0}/static/**/*{1}'.format(theme_path, extension)
|
||||
watched_globs.append(static_file_glob)
|
||||
|
||||
for glob in watched_globs:
|
||||
server.watch(glob, cached_build)
|
||||
|
||||
if OPEN_BROWSER_ON_SERVE:
|
||||
# Open site in default browser
|
||||
import webbrowser
|
||||
webbrowser.open("http://{host}:{port}".format(**CONFIG))
|
||||
|
||||
server.serve(host=CONFIG['host'], port=CONFIG['port'], root=CONFIG['deploy_path'])
|
||||
|
||||
{% if cloudfiles %}
|
||||
|
|
@ -130,7 +153,7 @@ def cf_upload(c):
|
|||
@task
|
||||
def publish(c):
|
||||
"""Publish to production via rsync"""
|
||||
c.run('pelican -s {settings_publish}'.format(**CONFIG))
|
||||
pelican_run('-s {settings_publish}'.format(**CONFIG))
|
||||
c.run(
|
||||
'rsync --delete --exclude ".DS_Store" -pthrvz -c '
|
||||
'-e "ssh -p {ssh_port}" '
|
||||
|
|
@ -147,3 +170,7 @@ def gh_pages(c):
|
|||
'-m {commit_message} '
|
||||
'{deploy_path} -p'.format(**CONFIG))
|
||||
{% endif %}
|
||||
|
||||
def pelican_run(cmd):
|
||||
cmd += ' ' + program.core.remainder # allows to pass-through args to pelican
|
||||
pelican_main(shlex.split(cmd))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "pelican"
|
||||
version = "4.2.0"
|
||||
version = "4.6.0"
|
||||
description = "Static site generator supporting Markdown and reStructuredText"
|
||||
authors = ["Justin Mayer <entrop@gmail.com>"]
|
||||
license = "AGPLv3"
|
||||
|
|
@ -15,48 +15,53 @@ classifiers = [
|
|||
"Development Status :: 5 - Production/Stable",
|
||||
"Environment :: Console",
|
||||
"Framework :: Pelican",
|
||||
"License :: OSI Approved :: GNU Affero General Public License v3",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"Topic :: Internet :: WWW/HTTP",
|
||||
"Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Content Management System",
|
||||
"Topic :: Internet :: WWW/HTTP :: Site Management",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Topic :: Text Processing :: Markup :: Markdown",
|
||||
"Topic :: Text Processing :: Markup :: HTML",
|
||||
"Topic :: Text Processing :: Markup :: reStructuredText",
|
||||
]
|
||||
|
||||
[tool.poetry.urls]
|
||||
"Funding" = "https://donate.getpelican.com/"
|
||||
"Tracker" = "https://github.com/getpelican/pelican/issues"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.6"
|
||||
feedgenerator = "^1.9"
|
||||
jinja2 = "~2.11"
|
||||
pygments = "~2.6.1"
|
||||
pytz = "^2019.1"
|
||||
blinker = "^1.4"
|
||||
unidecode = "^1.1"
|
||||
python-dateutil = "^2.8"
|
||||
docutils = "^0.15"
|
||||
markdown = {version = "~3.1.1", optional = true}
|
||||
blinker = ">=1.4"
|
||||
docutils = ">=0.16"
|
||||
feedgenerator = ">=1.9"
|
||||
jinja2 = ">=2.7"
|
||||
pygments = ">=2.6"
|
||||
python-dateutil = ">=2.8"
|
||||
pytz = ">=2020.1"
|
||||
unidecode = ">=1.1"
|
||||
markdown = {version = ">=3.1", optional = true}
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
BeautifulSoup4 = "^4.7"
|
||||
BeautifulSoup4 = "^4.9"
|
||||
jinja2 = "~2.11"
|
||||
lxml = "^4.3"
|
||||
markdown = "~3.1.1"
|
||||
markdown = "~3.3.4"
|
||||
typogrify = "^2.0"
|
||||
sphinx = "=1.4.9"
|
||||
sphinx_rtd_theme = "^0.4.3"
|
||||
sphinx = "^3.0"
|
||||
sphinx_rtd_theme = "^0.5"
|
||||
livereload = "^2.6"
|
||||
mock = "^3.0"
|
||||
pytest = "~5.3.5"
|
||||
psutil = {version = "^5.7", optional = true}
|
||||
pygments = "~2.8"
|
||||
pytest = "^6.0"
|
||||
pytest-cov = "^2.8"
|
||||
pytest-pythonpath = "^0.7.3"
|
||||
pytest-sugar = "^0.9.2"
|
||||
pytest-xdist = "^1.31"
|
||||
tox = "^3.13"
|
||||
flake8 = "^3.7"
|
||||
pytest-sugar = "^0.9.4"
|
||||
pytest-xdist = "^2.0"
|
||||
tox = {version = "^3.13", optional = true}
|
||||
flake8 = "^3.8"
|
||||
flake8-import-order = "^0.18.1"
|
||||
invoke = "^1.3"
|
||||
isort = "^4.3.21"
|
||||
isort = "^5.2"
|
||||
black = {version = "^19.10b0", allow-prereleases = true}
|
||||
|
||||
[tool.poetry.extras]
|
||||
|
|
@ -64,6 +69,10 @@ markdown = ["markdown"]
|
|||
|
||||
[tool.poetry.scripts]
|
||||
pelican = "pelican.__main__:main"
|
||||
pelican-import = "pelican.tools.pelican_import:main"
|
||||
pelican-plugins = "pelican.plugins._utils:list_plugins"
|
||||
pelican-quickstart = "pelican.tools.pelican_quickstart:main"
|
||||
pelican-themes = "pelican.tools.pelican_themes:main"
|
||||
|
||||
[tool.autopub]
|
||||
project-name = "Pelican"
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
# Tests
|
||||
Pygments==2.6.1
|
||||
pytest==5.3.5
|
||||
Pygments==2.8.1
|
||||
pytest
|
||||
pytest-cov
|
||||
pytest-xdist
|
||||
pytest-xdist[psutil]
|
||||
|
||||
# Optional Packages
|
||||
Markdown >= 3.1
|
||||
Markdown==3.3.4
|
||||
BeautifulSoup4
|
||||
lxml
|
||||
typogrify
|
||||
|
|
|
|||
24
setup.py
24
setup.py
|
|
@ -3,12 +3,12 @@
|
|||
from os import walk
|
||||
from os.path import join, relpath
|
||||
|
||||
from setuptools import setup
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
|
||||
version = "4.2.0"
|
||||
version = "4.6.0"
|
||||
|
||||
requires = ['feedgenerator >= 1.9', 'jinja2 >= 2.11', 'pygments',
|
||||
requires = ['feedgenerator >= 1.9', 'jinja2 >= 2.7', 'pygments',
|
||||
'docutils>=0.15', 'pytz >= 0a', 'blinker', 'unidecode',
|
||||
'python-dateutil']
|
||||
|
||||
|
|
@ -44,19 +44,15 @@ setup(
|
|||
keywords='static web site generator SSG reStructuredText Markdown',
|
||||
license='AGPLv3',
|
||||
long_description=description,
|
||||
packages=['pelican', 'pelican.tools', 'pelican.plugins'],
|
||||
package_data={
|
||||
# we manually collect the package data, as opposed to using,
|
||||
# include_package_data=True because we don't want the tests to be
|
||||
# included automatically as package data (MANIFEST.in is too greedy)
|
||||
long_description_content_type='text/x-rst',
|
||||
packages=find_packages(),
|
||||
include_package_data=True, # includes all in MANIFEST.in if in package
|
||||
# NOTE : This will collect any files that happen to be in the themes
|
||||
# directory, even though they may not be checked into version control.
|
||||
package_data={ # pelican/themes is not a package, so include manually
|
||||
'pelican': [relpath(join(root, name), 'pelican')
|
||||
for root, _, names in walk(join('pelican', 'themes'))
|
||||
for name in names],
|
||||
'pelican.tools': [relpath(join(root, name), join('pelican', 'tools'))
|
||||
for root, _, names in walk(join('pelican',
|
||||
'tools',
|
||||
'templates'))
|
||||
for name in names],
|
||||
},
|
||||
install_requires=requires,
|
||||
extras_require={
|
||||
|
|
@ -70,9 +66,9 @@ setup(
|
|||
'License :: OSI Approved :: GNU Affero General Public License v3',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
|
|
|
|||
13
tasks.py
13
tasks.py
|
|
@ -5,7 +5,7 @@ from shutil import which
|
|||
from invoke import task
|
||||
|
||||
PKG_NAME = "pelican"
|
||||
PKG_PATH = Path("pelican")
|
||||
PKG_PATH = Path(PKG_NAME)
|
||||
DOCS_PORT = os.environ.get("DOCS_PORT", 8000)
|
||||
BIN_DIR = "bin" if os.name != "nt" else "Scripts"
|
||||
ACTIVE_VENV = os.environ.get("VIRTUAL_ENV", None)
|
||||
|
|
@ -14,7 +14,7 @@ VENV_PATH = Path(ACTIVE_VENV) if ACTIVE_VENV else (VENV_HOME / PKG_NAME)
|
|||
VENV = str(VENV_PATH.expanduser())
|
||||
VENV_BIN = Path(VENV) / Path(BIN_DIR)
|
||||
|
||||
TOOLS = ["poetry", "pre-commit"]
|
||||
TOOLS = ["poetry", "pre-commit", "psutil"]
|
||||
POETRY = which("poetry") if which("poetry") else (VENV_BIN / "poetry")
|
||||
PRECOMMIT = (
|
||||
which("pre-commit") if which("pre-commit") else (VENV_BIN / "pre-commit")
|
||||
|
|
@ -42,7 +42,8 @@ def docserve(c):
|
|||
@task
|
||||
def tests(c):
|
||||
"""Run the test suite"""
|
||||
c.run(f"{VENV_BIN}/pytest", pty=True)
|
||||
PTY = True if os.name != "nt" else False
|
||||
c.run(f"{VENV_BIN}/pytest", pty=PTY)
|
||||
|
||||
|
||||
@task
|
||||
|
|
@ -64,19 +65,17 @@ def isort(c, check=False, diff=False):
|
|||
if diff:
|
||||
diff_flag = "--diff"
|
||||
c.run(
|
||||
f"{VENV_BIN}/isort {check_flag} {diff_flag} --recursive {PKG_PATH}/* tasks.py"
|
||||
f"{VENV_BIN}/isort {check_flag} {diff_flag} ."
|
||||
)
|
||||
|
||||
|
||||
@task
|
||||
def flake8(c):
|
||||
c.run(f"{VENV_BIN}/flake8 {PKG_PATH} tasks.py")
|
||||
c.run(f"git diff HEAD | {VENV_BIN}/flake8 --diff --max-line-length=88")
|
||||
|
||||
|
||||
@task
|
||||
def lint(c):
|
||||
isort(c, check=True)
|
||||
black(c, check=True)
|
||||
flake8(c)
|
||||
|
||||
|
||||
|
|
|
|||
10
tox.ini
10
tox.ini
|
|
@ -1,12 +1,12 @@
|
|||
[tox]
|
||||
envlist = py{3.5,3.6,3.7,3.8},docs,flake8
|
||||
envlist = py{3.6,3.7,3.8,3.9},docs,flake8
|
||||
|
||||
[testenv]
|
||||
basepython =
|
||||
py3.5: python3.5
|
||||
py3.6: python3.6
|
||||
py3.7: python3.7
|
||||
py3.8: python3.8
|
||||
py3.9: python3.9
|
||||
passenv = *
|
||||
usedevelop=True
|
||||
deps =
|
||||
|
|
@ -17,7 +17,7 @@ commands =
|
|||
pytest -s --cov=pelican pelican
|
||||
|
||||
[testenv:docs]
|
||||
basepython = python3.6
|
||||
basepython = python3.7
|
||||
deps =
|
||||
-rrequirements/docs.pip
|
||||
changedir = docs
|
||||
|
|
@ -28,7 +28,7 @@ commands =
|
|||
filterwarnings =
|
||||
default::DeprecationWarning
|
||||
error:.*:Warning:pelican
|
||||
addopts = -n 2 -r a
|
||||
addopts = -n auto -r a
|
||||
|
||||
[flake8]
|
||||
application-import-names = pelican
|
||||
|
|
@ -36,7 +36,7 @@ import-order-style = cryptography
|
|||
max-line-length = 88
|
||||
|
||||
[testenv:flake8]
|
||||
basepython = python3.6
|
||||
basepython = python3.7
|
||||
deps =
|
||||
-rrequirements/style.pip
|
||||
commands =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue