mirror of
https://github.com/getpelican/pelican.git
synced 2026-06-01 07:06:55 +02:00
Merge branch 'main' into strip-toc-anchors-from-summaries
This commit is contained in:
commit
cdc88a5f1b
39 changed files with 1047 additions and 767 deletions
28
.github/ISSUE_TEMPLATE/---everything-else.md
vendored
28
.github/ISSUE_TEMPLATE/---everything-else.md
vendored
|
|
@ -1,28 +0,0 @@
|
|||
---
|
||||
name: "\U0001F5C3 Everything Else"
|
||||
about: Do you have a question/issue that does not fall into any of the other categories?
|
||||
title: ''
|
||||
labels: question
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Instead of a new issue, please consider submitting your question to:
|
||||
<https://github.com/getpelican/pelican/discussions>
|
||||
If for some reason you believe that your question warrants a new issue
|
||||
instead of a discussion thread, describe your question/issue here.
|
||||
This space is meant to be used for general questions
|
||||
that are not bugs, feature requests, or documentation issues.
|
||||
Before you submit this, let’s make sure of a few things.
|
||||
Please make sure the following boxes are ticked if they are correct.
|
||||
If not, please try and fulfill them first.
|
||||
-->
|
||||
|
||||
<!-- Checked checkbox should look like this: [x] -->
|
||||
- [ ] I have searched the [issues](https://github.com/getpelican/pelican/issues?q=is%3Aissue) (including closed ones) and believe that this is not a duplicate.
|
||||
- [ ] I have searched the [documentation](https://docs.getpelican.com/) and believe that my question is not covered.
|
||||
- [ ] I have carefully read the [How to Get Help](https://docs.getpelican.com/en/latest/contribute.html#how-to-get-help) section of the documentation.
|
||||
|
||||
## Issue
|
||||
<!-- Now feel free to write your issue, but please be descriptive! Thanks again 🙌 ❤️ -->
|
||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -2,6 +2,10 @@
|
|||
# Ref: https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: '🗃️ Everything Else'
|
||||
url: https://github.com/getpelican/pelican/discussions
|
||||
about: |
|
||||
Do you have a question/issue that does not fall into any of the other categories?
|
||||
- name: '💬 Pelican IRC Channel'
|
||||
url: https://web.libera.chat/?#pelican
|
||||
about: |
|
||||
|
|
|
|||
1
.github/dependabot.yml
vendored
1
.github/dependabot.yml
vendored
|
|
@ -7,3 +7,4 @@ updates:
|
|||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 0
|
||||
|
|
|
|||
48
.github/workflows/github_pages.yml
vendored
48
.github/workflows/github_pages.yml
vendored
|
|
@ -22,10 +22,15 @@ on:
|
|||
default: ""
|
||||
description: "The GitHub repo URL of a custom theme to use, for example: 'https://github.com/seanh/sidecar.git'"
|
||||
type: string
|
||||
theme-checkout:
|
||||
required: false
|
||||
default: ""
|
||||
description: "Git ref (branch, tag or commit) of the theme repo to checkout. This can be used to pin the version of your theme. If not specified defaults to the theme repo's default branch."
|
||||
type: string
|
||||
python:
|
||||
required: false
|
||||
default: "3.12"
|
||||
description: "The version of Python to use, for example: '3.12' (to use the most recent version of Python 3.12, this is faster) or '3.12.1' (to use an exact version, slower)"
|
||||
default: "3.14"
|
||||
description: "The version of Python to use, for example: '3.14' (to use the most recent version of Python 3.14, this is faster) or '3.14.0' (to use an exact version, slower)"
|
||||
type: string
|
||||
siteurl:
|
||||
required: false
|
||||
|
|
@ -42,6 +47,11 @@ on:
|
|||
default: true
|
||||
description: "Whether to deploy the site. If true then build the site and deploy it. If false then just test that the site builds successfully but don't deploy anything."
|
||||
type: boolean
|
||||
stork:
|
||||
required: false
|
||||
default: false
|
||||
description: "Whether to add Stork search tool. If true, it will be installed on runner."
|
||||
type: boolean
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
|
|
@ -51,17 +61,23 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ inputs.python }}
|
||||
- name: Checkout theme
|
||||
- name: Clone theme
|
||||
if: ${{ inputs.theme }}
|
||||
run: git clone '${{ inputs.theme }}' .theme
|
||||
- name: Checkout theme ref
|
||||
if: ${{ inputs.theme && inputs.theme-checkout }}
|
||||
run: git -C .theme checkout '${{ inputs.theme-checkout }}'
|
||||
- name: Configure GitHub Pages
|
||||
id: pages
|
||||
uses: actions/configure-pages@v5
|
||||
- name: Install Stork
|
||||
if: ${{ inputs.stork }}
|
||||
run: cargo install stork-search --locked
|
||||
- name: Install requirements
|
||||
run: pip install ${{ inputs.requirements }}
|
||||
- name: Build Pelican site
|
||||
|
|
@ -82,13 +98,31 @@ jobs:
|
|||
subprocess.run(cmd, shell=True, check=True)
|
||||
- name: Fix permissions
|
||||
run: |
|
||||
chmod -c -R +rX "${{ inputs.output-path }}" | while read line; do
|
||||
chmod -c -R +rX "${{ inputs.output-path }}" | while read -r line; do
|
||||
echo "::warning title=Invalid file permissions automatically fixed::$line"
|
||||
done
|
||||
- name: Archive artifact
|
||||
shell: sh
|
||||
run: |
|
||||
echo "::group::Archive artifact"
|
||||
tar \
|
||||
--dereference \
|
||||
--hard-dereference \
|
||||
--directory "$OUTPUT_PATH" \
|
||||
-cvf "$RUNNER_TEMP/artifact.tar" \
|
||||
--exclude=.git \
|
||||
--exclude=.github \
|
||||
.
|
||||
echo "::endgroup::"
|
||||
env:
|
||||
OUTPUT_PATH: ${{ inputs.output-path }}
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
path: ${{ inputs.output-path }}
|
||||
name: github-pages
|
||||
path: ${{ runner.temp }}/artifact.tar
|
||||
retention-days: 1
|
||||
if-no-files-found: error
|
||||
deploy:
|
||||
concurrency:
|
||||
group: "pages"
|
||||
|
|
|
|||
23
.github/workflows/main.yml
vendored
23
.github/workflows/main.yml
vendored
|
|
@ -15,15 +15,12 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu, macos, windows]
|
||||
python: ["3.10", "3.11", "3.12", "3.13"]
|
||||
include:
|
||||
- os: ubuntu
|
||||
python: "3.9"
|
||||
python: ["3.11", "3.12", "3.13", "3.14"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up Python ${{ matrix.python }}
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
cache: "pip"
|
||||
|
|
@ -50,7 +47,7 @@ jobs:
|
|||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: pdm-project/setup-pdm@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
|
@ -68,7 +65,7 @@ jobs:
|
|||
name: Test build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: pdm-project/setup-pdm@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
|
@ -86,9 +83,9 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.11"
|
||||
cache: "pip"
|
||||
|
|
@ -98,7 +95,7 @@ jobs:
|
|||
- name: Check
|
||||
run: tox -e docs
|
||||
- name: cache the docs for inspection
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: docs
|
||||
path: docs/_build/html/
|
||||
|
|
@ -115,12 +112,12 @@ jobs:
|
|||
id-token: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ repos:
|
|||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# ruff version should match the one in pyproject.toml
|
||||
rev: v0.12.2
|
||||
rev: v0.12.7
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ version: 2
|
|||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.10"
|
||||
python: "3.11"
|
||||
|
||||
# Build HTML & PDF formats
|
||||
formats:
|
||||
|
|
|
|||
70
docs/_templates/page.html
vendored
70
docs/_templates/page.html
vendored
|
|
@ -4,14 +4,16 @@
|
|||
{{ super() }}
|
||||
{% include "partials/icons.html" %}
|
||||
|
||||
<input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation">
|
||||
<input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc">
|
||||
<label class="overlay sidebar-overlay" for="__navigation">
|
||||
<div class="visually-hidden">Hide navigation sidebar</div>
|
||||
</label>
|
||||
<label class="overlay toc-overlay" for="__toc">
|
||||
<div class="visually-hidden">Hide table of contents sidebar</div>
|
||||
</label>
|
||||
<input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation" aria-label="Toggle site navigation sidebar">
|
||||
<input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc" aria-label="Toggle table of contents sidebar">
|
||||
<label class="overlay sidebar-overlay" for="__navigation"></label>
|
||||
<label class="overlay toc-overlay" for="__toc"></label>
|
||||
|
||||
<a class="skip-to-content muted-link" href="#furo-main-content">
|
||||
{%- trans -%}
|
||||
Skip to content
|
||||
{%- endtrans -%}
|
||||
</a>
|
||||
|
||||
{% if theme_announcement -%}
|
||||
<div class="announcement">
|
||||
|
|
@ -25,8 +27,7 @@
|
|||
<header class="mobile-header">
|
||||
<div class="header-left">
|
||||
<label class="nav-overlay-icon" for="__navigation">
|
||||
<div class="visually-hidden">Toggle site navigation sidebar</div>
|
||||
<i class="icon"><svg><use href="#svg-menu"></use></svg></i>
|
||||
<span class="icon"><svg><use href="#svg-menu"></use></svg></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
|
|
@ -34,16 +35,15 @@
|
|||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
<button class="theme-toggle">
|
||||
<div class="visually-hidden">Toggle Light / Dark / Auto color theme</div>
|
||||
<svg class="theme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
|
||||
<button class="theme-toggle" aria-label="Toggle Light / Dark / Auto color theme">
|
||||
<svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
|
||||
<svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
|
||||
<svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
|
||||
<svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
<label class="toc-overlay-icon toc-header-icon{% if furo_hide_toc %} no-toc{% endif %}" for="__toc">
|
||||
<div class="visually-hidden">Toggle table of contents sidebar</div>
|
||||
<i class="icon"><svg><use href="#svg-toc"></use></svg></i>
|
||||
<span class="icon"><svg><use href="#svg-toc"></use></svg></span>
|
||||
</label>
|
||||
</div>
|
||||
</header>
|
||||
|
|
@ -68,26 +68,46 @@
|
|||
<span>{% trans %}Back to top{% endtrans %}</span>
|
||||
</a>
|
||||
<div class="content-icon-container">
|
||||
{% if theme_top_of_page_button == "edit" -%}
|
||||
{%- include "components/edit-this-page.html" with context -%}
|
||||
{%- elif theme_top_of_page_button != None -%}
|
||||
{{ warning("Got an unsupported value for 'top_of_page_button'") }}
|
||||
{% if theme_top_of_page_button != "edit" -%}
|
||||
{{ warning("Got configuration for 'top_of_page_button': this is deprecated.") }}
|
||||
{%- endif -%}
|
||||
|
||||
{%- if theme_top_of_page_buttons == "" -%}
|
||||
{% if theme_top_of_page_button == None -%}
|
||||
{#- We respect the old configuration of disabling all the buttons -#}
|
||||
{%- set theme_top_of_page_buttons = [] -%}
|
||||
{% else %}
|
||||
{%- set theme_top_of_page_buttons = ["view", "edit"] -%}
|
||||
{%- endif -%}
|
||||
{% else -%}
|
||||
{% if theme_top_of_page_button != "edit" -%}
|
||||
{%- set theme_top_of_page_buttons = [] -%}
|
||||
{{ warning("Got configuration for both 'top_of_page_button' and 'top_of_page_buttons', ignoring both and removing all top of page buttons.") }}
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{% for button in theme_top_of_page_buttons -%}
|
||||
{% if button == "view" %}
|
||||
{%- include "components/view-this-page.html" with context -%}
|
||||
{% elif button == "edit" %}
|
||||
{%- include "components/edit-this-page.html" with context -%}
|
||||
{% else %}
|
||||
{{ warning("Got an unsupported value in 'top_of_page_buttons' for theme configuration") }}
|
||||
{% endif %}
|
||||
{%- endfor -%}
|
||||
{#- Theme toggle -#}
|
||||
<div class="theme-toggle-container theme-toggle-content">
|
||||
<button class="theme-toggle">
|
||||
<div class="visually-hidden">Toggle Light / Dark / Auto color theme</div>
|
||||
<svg class="theme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
|
||||
<button class="theme-toggle" aria-label="Toggle Light / Dark / Auto color theme">
|
||||
<svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
|
||||
<svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
|
||||
<svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
|
||||
<svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
<label class="toc-overlay-icon toc-content-icon{% if furo_hide_toc %} no-toc{% endif %}" for="__toc">
|
||||
<div class="visually-hidden">Toggle table of contents sidebar</div>
|
||||
<i class="icon"><svg><use href="#svg-toc"></use></svg></i>
|
||||
<span class="icon"><svg><use href="#svg-toc"></use></svg></span>
|
||||
</label>
|
||||
</div>
|
||||
<article role="main">
|
||||
<article role="main" id="furo-main-content">
|
||||
{% block content %}{{ body }}{% endblock %}
|
||||
</article>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,12 +2,7 @@ import datetime
|
|||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
import tomllib
|
||||
else:
|
||||
import tomli as tomllib
|
||||
|
||||
import tomllib
|
||||
|
||||
sys.path.append(os.path.abspath(os.pardir))
|
||||
|
||||
|
|
@ -32,7 +27,7 @@ source_suffix = ".rst"
|
|||
master_doc = "index"
|
||||
project = project_data.get("name").upper()
|
||||
year = datetime.datetime.fromtimestamp(
|
||||
int(os.environ.get("SOURCE_DATE_EPOCH", time.time())), datetime.timezone.utc
|
||||
int(os.environ.get("SOURCE_DATE_EPOCH", time.time())), datetime.UTC
|
||||
).year
|
||||
project_copyright = f"2010–{year}" # noqa: RUF001
|
||||
exclude_patterns = ["_build"]
|
||||
|
|
|
|||
|
|
@ -112,6 +112,11 @@ If you want to include metadata in templates outside the article context (e.g.,
|
|||
|
||||
{% if article and article.modified %}
|
||||
|
||||
.. note::
|
||||
|
||||
Because the colon symbol (``:``) is used as a separator, be aware that
|
||||
metadata field names *containing* a colon will probably not work.
|
||||
|
||||
How do I make my output folder structure identical to my content hierarchy?
|
||||
===========================================================================
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PELICAN 4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-07 16:25+0800\n"
|
||||
"PO-Revision-Date: 2024-06-27 19:00+0800\n"
|
||||
"POT-Creation-Date: 2026-02-02 10:32+0800\n"
|
||||
"PO-Revision-Date: 2026-02-02 10:32+0800\n"
|
||||
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
|
||||
"Language: zh_CN\n"
|
||||
"Language-Team: \n"
|
||||
|
|
@ -16,7 +16,7 @@ msgstr ""
|
|||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.16.0\n"
|
||||
"Generated-By: Babel 2.17.0\n"
|
||||
|
||||
#: ../../faq.rst:2 84467b3ab4b8411589855b3130e14406
|
||||
msgid "Frequently Asked Questions (FAQ)"
|
||||
|
|
@ -143,8 +143,9 @@ msgid ""
|
|||
" or add new templates, via the ``THEME_TEMPLATES_OVERRIDES`` variable. "
|
||||
"For example, to override the page template, you can define the location "
|
||||
"for your templates like this::"
|
||||
msgstr "当然可以,覆盖部分模板文件或是添加一些模板文件都是可以的,使用 ``THEME_TEMPLATES_OVERRIDES`` 变量即可。"
|
||||
"例如,若需要覆盖page的模板,可以向这样定义你自己的模板文件位置:"
|
||||
msgstr ""
|
||||
"当然可以,覆盖部分模板文件或是添加一些模板文件都是可以的,使用 ``THEME_TEMPLATES_OVERRIDES`` "
|
||||
"变量即可。例如,若需要覆盖page的模板,可以向这样定义你自己的模板文件位置:"
|
||||
|
||||
#: ../../faq.rst:77 a96870f0cad74996bec2469ea0c2e9e1
|
||||
msgid ""
|
||||
|
|
@ -198,51 +199,59 @@ msgid ""
|
|||
"(e.g., ``base.html``), the ``if`` statement should instead be::"
|
||||
msgstr "如果您想在其他模板(例如 ``base.html`` )中获取此元数据,则 ``if`` 语句应改为:"
|
||||
|
||||
#: ../../faq.rst:116 b78a678a165d40f4823fac2b19bcafc1
|
||||
#: ../../faq.rst:117 22fb499d05e041c4bea55515c5428685
|
||||
msgid ""
|
||||
"Because the colon symbol (``:``) is used as a separator, be aware that "
|
||||
"metadata field names *containing* a colon will probably not work."
|
||||
msgstr "因为冒号 (``:``) 已经用作分隔符,字段名称包含冒号的元数据可能不会起作用。"
|
||||
|
||||
#: ../../faq.rst:121 b78a678a165d40f4823fac2b19bcafc1
|
||||
msgid ""
|
||||
"How do I make my output folder structure identical to my content "
|
||||
"hierarchy?"
|
||||
msgstr "如何使得输出目录的结构和content目录的结构保持一致?"
|
||||
|
||||
#: ../../faq.rst:118 851d1019c070482991667cc024063d29
|
||||
#: ../../faq.rst:123 851d1019c070482991667cc024063d29
|
||||
msgid "Try these settings::"
|
||||
msgstr "可以尝试如下配置:"
|
||||
|
||||
#: ../../faq.rst:125 5195876e3f364a838d72b16c568263bc
|
||||
#: ../../faq.rst:130 5195876e3f364a838d72b16c568263bc
|
||||
msgid "How do I assign custom templates on a per-page basis?"
|
||||
msgstr "如何为某个页面指定某个模板?"
|
||||
|
||||
#: ../../faq.rst:127 2ddd3cf1fbf048b1819bcfc9b3691a12
|
||||
#: ../../faq.rst:132 2ddd3cf1fbf048b1819bcfc9b3691a12
|
||||
msgid ""
|
||||
"It's as simple as adding an extra line of metadata to any page or article"
|
||||
" that you want to have its own template. For example, this is how it "
|
||||
"would be handled for content in reST format::"
|
||||
msgstr "这非常简单,在任何页面或者文章中,都可以通过多添加一行元数据来指定特定模板。例如,在reST中,使用:"
|
||||
|
||||
#: ../../faq.rst:133 6f5eb40b4a5e4f83ab9d1cb48fefad57
|
||||
#: ../../faq.rst:138 6f5eb40b4a5e4f83ab9d1cb48fefad57
|
||||
msgid "For content in Markdown format::"
|
||||
msgstr "对于Markdown,则使用:"
|
||||
|
||||
#: ../../faq.rst:137 2e28d1bf074c437eb5017bf6f345bf71
|
||||
#: ../../faq.rst:142 2e28d1bf074c437eb5017bf6f345bf71
|
||||
msgid ""
|
||||
"Then just make sure your theme contains the relevant template file (e.g. "
|
||||
"``template_name.html``). If you just want to add a new custom template to"
|
||||
" an existing theme, you can also provide it in a directory specified by "
|
||||
"``THEME_TEMPLATES_OVERRIDES`` (see :ref:`settings/themes`)."
|
||||
msgstr ""
|
||||
"接着只要确保主题中有相对应的模板文件 (e.g. ``template_name.html``)。如果只是需要把一个自定义"
|
||||
"模板加到已有主题中,可以将其放在 ``THEME_TEMPLATES_OVERRIDES`` 指定的目录中 (详见 :ref:`settings/themes`)。"
|
||||
|
||||
#: ../../faq.rst:142 675e77f99f3c42bb8715c84a97c7a064
|
||||
#: ../../faq.rst:147 675e77f99f3c42bb8715c84a97c7a064
|
||||
msgid "How can I override the generated URL of a specific page or article?"
|
||||
msgstr "如何重写某一个页面或文章生成的URL?"
|
||||
|
||||
#: ../../faq.rst:144 7e518b99b29d4787addc732d57e94ed1
|
||||
#: ../../faq.rst:149 7e518b99b29d4787addc732d57e94ed1
|
||||
msgid ""
|
||||
"Include ``url`` and ``save_as`` metadata in any pages or articles that "
|
||||
"you want to override the generated URL. Here is an example page in reST "
|
||||
"format::"
|
||||
msgstr "在任意页面或文章中都可以添加 ``url`` 和 ``save_as`` 元数据,这样就可以重写URL了。下面以reST格式为例:"
|
||||
|
||||
#: ../../faq.rst:153 903306ecaed3483591b4ed2dcba3d183
|
||||
#: ../../faq.rst:158 903306ecaed3483591b4ed2dcba3d183
|
||||
msgid ""
|
||||
"With this metadata, the page will be written to "
|
||||
"``override/url/index.html`` and Pelican will use the URL "
|
||||
|
|
@ -251,18 +260,18 @@ msgstr ""
|
|||
"有了这样的元数据,此页面会保存为 ``override/url/index.html`` ,Pelican会将 ``override/url/``"
|
||||
" 作为链接到此页面的URL。"
|
||||
|
||||
#: ../../faq.rst:157 d80d84fcb6844e25a8452e29c4113181
|
||||
#: ../../faq.rst:162 d80d84fcb6844e25a8452e29c4113181
|
||||
msgid "How can I use a static page as my home page?"
|
||||
msgstr "如何使用一个静态页面作为主页?"
|
||||
|
||||
#: ../../faq.rst:159 e17a2e2dd9014109888bab9286ee607c
|
||||
#: ../../faq.rst:164 e17a2e2dd9014109888bab9286ee607c
|
||||
msgid ""
|
||||
"The override feature mentioned above can be used to specify a static page"
|
||||
" as your home page. The following Markdown example could be stored in "
|
||||
"``content/pages/home.md``::"
|
||||
msgstr "上一个问题中提到的特性可以用于实现此需求。下面例子中的Markdown文件保存为 ``content/pages/home.md`` :"
|
||||
|
||||
#: ../../faq.rst:169 b99ba0ca8656416cbdc38f3fa263b7eb
|
||||
#: ../../faq.rst:174 b99ba0ca8656416cbdc38f3fa263b7eb
|
||||
msgid ""
|
||||
"If the original blog index is still wanted, it can then be saved in a "
|
||||
"different location by setting ``INDEX_SAVE_AS = 'blog_index.html'`` for "
|
||||
|
|
@ -271,11 +280,11 @@ msgstr ""
|
|||
"如果仍需要原来的博客主页(即 ``'index'`` 直接模板),可以通过设置 ``INDEX_SAVE_AS = "
|
||||
"'blog_index.html'`` 将其存储在其他位置。"
|
||||
|
||||
#: ../../faq.rst:174 fca4725a57dd451fb3b0fb9df78f69b5
|
||||
#: ../../faq.rst:179 fca4725a57dd451fb3b0fb9df78f69b5
|
||||
msgid "What if I want to disable feed generation?"
|
||||
msgstr "可以禁用订阅源生成吗?"
|
||||
|
||||
#: ../../faq.rst:176 e9c08140e2ed44f189a7a156db027a3e
|
||||
#: ../../faq.rst:181 e9c08140e2ed44f189a7a156db027a3e
|
||||
msgid ""
|
||||
"To disable feed generation, all feed settings should be set to ``None``. "
|
||||
"All but three feed settings already default to ``None``, so if you want "
|
||||
|
|
@ -285,19 +294,19 @@ msgstr ""
|
|||
"要禁用订阅源,所有订阅源相关的配置都应被设为 ``None`` 。其中有三项设置默认为 ``None`` "
|
||||
",因此如果要彻底不生成订阅源,你只需要指定下面这些设置:"
|
||||
|
||||
#: ../../faq.rst:186 7820a481af4c4f44a40fb3ae80768a1d
|
||||
#: ../../faq.rst:191 7820a481af4c4f44a40fb3ae80768a1d
|
||||
msgid ""
|
||||
"The word ``None`` should not be surrounded by quotes. Please note that "
|
||||
"``None`` and ``''`` are not the same thing."
|
||||
msgstr "``None`` 两侧不需要加引号。请注意 ``None`` 和 ``''`` 不是同一个东西。"
|
||||
|
||||
#: ../../faq.rst:190 4fa2ffbf1c274ec396a0d756762c260d
|
||||
#: ../../faq.rst:195 4fa2ffbf1c274ec396a0d756762c260d
|
||||
msgid ""
|
||||
"I'm getting a warning about feeds generated without SITEURL being set "
|
||||
"properly"
|
||||
msgstr "Pelican警告说由于SITEURL设置不正确,无法正常生成订阅源"
|
||||
|
||||
#: ../../faq.rst:192 8d52f14f6b03476897dfb15c188a961a
|
||||
#: ../../faq.rst:197 8d52f14f6b03476897dfb15c188a961a
|
||||
msgid ""
|
||||
"`RSS and Atom feeds require all URL links to be absolute "
|
||||
"<https://validator.w3.org/feed/docs/rss2.html#comments>`_. In order to "
|
||||
|
|
@ -308,17 +317,17 @@ msgstr ""
|
|||
"<https://validator.w3.org/feed/docs/rss2.html#comments>`_ "
|
||||
"。为了使得Pelican能正确生成链接,你需要将站点的 ``SITEURL`` 设置为完整路径。"
|
||||
|
||||
#: ../../faq.rst:197 1412ceb735d44a30b58db3241248e7ec
|
||||
#: ../../faq.rst:202 1412ceb735d44a30b58db3241248e7ec
|
||||
msgid ""
|
||||
"Feeds are still generated when this warning is displayed, but links "
|
||||
"within may be malformed and thus the feed may not validate."
|
||||
msgstr "虽然Pelican提出了警告,但是仍会生成订阅源,但其中的链接可能是无效的,这会导致订阅源不可用。"
|
||||
|
||||
#: ../../faq.rst:201 20cadccc527e4ebda08eac9ed34f5055
|
||||
#: ../../faq.rst:206 20cadccc527e4ebda08eac9ed34f5055
|
||||
msgid "Can I force Atom feeds to show only summaries instead of article content?"
|
||||
msgstr "可以让Atom订阅源只显示摘要,不显示文章内容吗?"
|
||||
|
||||
#: ../../faq.rst:203 9c45ba2ec5c6402e86e89661b943d1ad
|
||||
#: ../../faq.rst:208 9c45ba2ec5c6402e86e89661b943d1ad
|
||||
msgid ""
|
||||
"Instead of having to open a separate browser window to read articles, the"
|
||||
" overwhelming majority of folks who use feed readers prefer to read "
|
||||
|
|
@ -335,11 +344,11 @@ msgstr ""
|
|||
" ``content`` "
|
||||
"字段,因此Pelican在发布RSS时默认只包含摘要(当然也可以设置为包含文章内容)。Pelican在订阅源生成上的如此行为就可以让用户自行选择订阅类型:包含了完整内容的Atom或是只包含摘要的RSS。"
|
||||
|
||||
#: ../../faq.rst:214 bf0d4ca837f74d9ab6618db6306c6a70
|
||||
#: ../../faq.rst:219 bf0d4ca837f74d9ab6618db6306c6a70
|
||||
msgid "Is Pelican only suitable for blogs?"
|
||||
msgstr "Pelican只适合用于博客吗?"
|
||||
|
||||
#: ../../faq.rst:216 49697f375cfc49b08f5d0c2297d15028
|
||||
#: ../../faq.rst:221 49697f375cfc49b08f5d0c2297d15028
|
||||
msgid ""
|
||||
"No. Pelican can be easily configured to create and maintain any type of "
|
||||
"static site. This may require a little customization of your theme and "
|
||||
|
|
@ -349,13 +358,13 @@ msgid ""
|
|||
"tag-related pages via::"
|
||||
msgstr "不是的。Pelican可以方便地用于创建维护任何静态站点,为此你需要对主题和配置做一些定制。例如,如果要为你的产品构建一个宣传网站,即不需要使用标签特性,从主题中移除与标签相关的HTML代码即可。另外,还可以通过下面的设置来禁用标签相关页面的生成:"
|
||||
|
||||
#: ../../faq.rst:226 0a59dd7209554237912579b362d07788
|
||||
#: ../../faq.rst:231 0a59dd7209554237912579b362d07788
|
||||
msgid ""
|
||||
"Why does Pelican always write all HTML files even with content caching "
|
||||
"enabled?"
|
||||
msgstr "启用内容缓存后,为什么Pelican仍会每次都写入所有HTML文件?"
|
||||
|
||||
#: ../../faq.rst:228 6291b82d02fc4450a79d1200b5d04f62
|
||||
#: ../../faq.rst:233 6291b82d02fc4450a79d1200b5d04f62
|
||||
msgid ""
|
||||
"In order to reliably determine whether the HTML output is different "
|
||||
"before writing it, a large part of the generation environment including "
|
||||
|
|
@ -368,7 +377,7 @@ msgid ""
|
|||
"reliable."
|
||||
msgstr "为了确定HTML输出确实和之前的不同,模板上下文、插件等很多生成环境都需要保存并比较某种哈希值(对于不可哈希的内容类型还需要进行一些额外处理)。另外,由于插件、分页等内容的存在,输出的HTML很可能会与之前不同。因此,考虑到处理时间和存储空间,每次都重新写入全部HTML会更快更可靠。"
|
||||
|
||||
#: ../../faq.rst:237 5cc5e1361f914c92b0670030f0c83f5d
|
||||
#: ../../faq.rst:242 5cc5e1361f914c92b0670030f0c83f5d
|
||||
msgid ""
|
||||
"However, this means that the modification time of the files changes every"
|
||||
" time, so a ``rsync`` based upload will transfer them even if their "
|
||||
|
|
@ -380,11 +389,11 @@ msgstr ""
|
|||
"上传时会把没有变化的内容也进行上传。一个简便的解决方法就是给 ``rsync`` 加上 ``--checksum`` "
|
||||
"选项,这会比Pelican在生成时进行校验更快。"
|
||||
|
||||
#: ../../faq.rst:244 b24c40be89b94f3b980cbbda38d46115
|
||||
#: ../../faq.rst:249 b24c40be89b94f3b980cbbda38d46115
|
||||
msgid "How to process only a subset of all articles?"
|
||||
msgstr "如何只处理一部分文章?"
|
||||
|
||||
#: ../../faq.rst:246 fa34a90481f44ace83ee16401543ce09
|
||||
#: ../../faq.rst:251 fa34a90481f44ace83ee16401543ce09
|
||||
msgid ""
|
||||
"It is often useful to process only e.g. 10 articles for debugging "
|
||||
"purposes. This can be achieved by explicitly specifying only the "
|
||||
|
|
@ -395,11 +404,11 @@ msgstr ""
|
|||
"简便起见,在调试时可能只需要处理几篇文章。可以直接在配置项 ``ARTICLE_PATHS`` 中添加需要处理文章的文件名。可以通过像 ``cd "
|
||||
"content; find -name '*.md' | head -n 10`` 这样的命令获取文章文件名的列表。"
|
||||
|
||||
#: ../../faq.rst:252 0fa566e3aa084cb9b04e0cee32684222
|
||||
#: ../../faq.rst:257 0fa566e3aa084cb9b04e0cee32684222
|
||||
msgid "My tag cloud is missing/broken since I upgraded Pelican"
|
||||
msgstr "在升级Pelican后,标签云消失或不可用了"
|
||||
|
||||
#: ../../faq.rst:254 0bd1304a12c24f048b227c68391b148c
|
||||
#: ../../faq.rst:259 0bd1304a12c24f048b227c68391b148c
|
||||
msgid ""
|
||||
"In an ongoing effort to streamline Pelican, tag cloud generation has been"
|
||||
" moved out of Pelican core and into a separate `plugin "
|
||||
|
|
@ -410,11 +419,11 @@ msgstr ""
|
|||
"<https://github.com/pelican-plugins/tag-cloud>`_ 中。查看 :ref:`plugins` "
|
||||
"文档获取更多关于Pelican插件系统的信息。"
|
||||
|
||||
#: ../../faq.rst:260 1833dfba94c74f4bb9e9f0a112ed3e0f
|
||||
#: ../../faq.rst:265 1833dfba94c74f4bb9e9f0a112ed3e0f
|
||||
msgid "Since I upgraded Pelican my pages are no longer rendered"
|
||||
msgstr "升级Pelican后,一些页面没有被渲染"
|
||||
|
||||
#: ../../faq.rst:262 576e5c2338ba4c43a51bb562301ad0c2
|
||||
#: ../../faq.rst:267 576e5c2338ba4c43a51bb562301ad0c2
|
||||
msgid ""
|
||||
"Pages were available to themes as lowercase ``pages`` and uppercase "
|
||||
"``PAGES``. To bring this inline with the :ref:`templates-variables` "
|
||||
|
|
@ -426,15 +435,15 @@ msgstr ""
|
|||
"variables` 一节中的内容保持一致,大写的 ``PAGES`` 被删除了。只要将主题中的 ``PAGES`` 替换为 ``pages`` "
|
||||
",问题即可解决。例如将原先的:"
|
||||
|
||||
#: ../../faq.rst:269 355512b9f6b34ece9b6baed128b2ca4d
|
||||
#: ../../faq.rst:274 355512b9f6b34ece9b6baed128b2ca4d
|
||||
msgid "with something like::"
|
||||
msgstr "替换为:"
|
||||
|
||||
#: ../../faq.rst:274 99ef769943fe41c4a37ca951e905b2ba
|
||||
#: ../../faq.rst:279 99ef769943fe41c4a37ca951e905b2ba
|
||||
msgid "How can I stop Pelican from trying to parse my static files as content?"
|
||||
msgstr "如何避免让Pelican将我的静态文件解析为内容文件?(译者注:例如要将一个HTML文件作为静态文件)?"
|
||||
msgstr "如何避免让Pelican将我的静态文件解析为内容文件?(译者注:例如要将一个HTML文件作为静态文件)"
|
||||
|
||||
#: ../../faq.rst:276 4efb20c5b82d41afb07151599fa189dd
|
||||
#: ../../faq.rst:281 4efb20c5b82d41afb07151599fa189dd
|
||||
msgid ""
|
||||
"Pelican's article and page generators run before it's static generator. "
|
||||
"That means if you use a setup similar to the default configuration, where"
|
||||
|
|
@ -447,7 +456,7 @@ msgstr ""
|
|||
"配置项中,所有以有效内容文件后缀结尾的文件( ``.html`` 、 ``.rst`` 、 ``.md`` "
|
||||
"等)都会被视为文章或者页面,而不是静态文件。"
|
||||
|
||||
#: ../../faq.rst:282 d959eb6a67fe440caa70105e1692bf93
|
||||
#: ../../faq.rst:287 d959eb6a67fe440caa70105e1692bf93
|
||||
msgid ""
|
||||
"To circumvent this issue either use the appropriate ``*_EXCLUDES`` "
|
||||
"setting or disable the offending reader via ``READERS`` if you don't need"
|
||||
|
|
@ -456,11 +465,11 @@ msgstr ""
|
|||
"为了避免这个问题,使用合适的 ``*_EXCLUDES`` 配置,在必要时还可以通过 ``READERS`` "
|
||||
"配置项来直接禁用产生问题的reader。"
|
||||
|
||||
#: ../../faq.rst:286 5e64dc4b6fad4e7ea07278f5a2529e89
|
||||
#: ../../faq.rst:291 5e64dc4b6fad4e7ea07278f5a2529e89
|
||||
msgid "Why is [arbitrary Markdown syntax] not supported?"
|
||||
msgstr "为什么不是所有的Markdown语法都支持?"
|
||||
|
||||
#: ../../faq.rst:288 6872a70ec1434c41a78d465271761c69
|
||||
#: ../../faq.rst:293 6872a70ec1434c41a78d465271761c69
|
||||
msgid ""
|
||||
"Pelican does not directly handle Markdown processing and instead "
|
||||
"delegates that task to the Python-Markdown_ project, the core of which "
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -7,8 +7,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PELICAN 4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-06-24 19:06+0800\n"
|
||||
"PO-Revision-Date: 2024-06-27 19:00+0800\n"
|
||||
"POT-Creation-Date: 2026-02-02 10:32+0800\n"
|
||||
"PO-Revision-Date: 2026-02-02 10:32+0800\n"
|
||||
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
|
||||
"Language: zh_CN\n"
|
||||
"Language-Team: \n"
|
||||
|
|
@ -16,30 +16,34 @@ msgstr ""
|
|||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.15.0\n"
|
||||
"Generated-By: Babel 2.17.0\n"
|
||||
|
||||
#: ../../_templates/page.html:68 697aead398874e06aa15cfd74d134745
|
||||
#: ../../_templates/page.html:13 d28434a1f790406f866556f17fe43bea
|
||||
msgid "Skip to content"
|
||||
msgstr ""
|
||||
|
||||
#: ../../_templates/page.html:68 11a1e7e70c0542dcb853ce6d667b4b13
|
||||
msgid "Back to top"
|
||||
msgstr "返回顶部"
|
||||
|
||||
#: ../../_templates/page.html:101 f91a64e54aae49c2bd09a944ea693193
|
||||
#: ../../_templates/page.html:121 b65dfb48967147f688c1d2166a0d3e60
|
||||
msgid "Next"
|
||||
msgstr "下一节"
|
||||
|
||||
#: ../../_templates/page.html:113 6c3ad069077b4e2cb6e1f77cc2962881
|
||||
#: ../../_templates/page.html:133 44ccbbca34f24a5fb1083bcda42d2399
|
||||
msgid "Previous"
|
||||
msgstr "前一节"
|
||||
|
||||
#: ../../_templates/page.html:116 e83e03d0b50c4065a9f87db25a23b3ee
|
||||
#: ../../_templates/page.html:136 fd17897083a54a929cff164a233bd4d7
|
||||
msgid "Home"
|
||||
msgstr "首页"
|
||||
|
||||
#: ../../_templates/page.html:129 1d0fdb4c0b4e420283101ba5c21ac985
|
||||
#: ../../_templates/page.html:149 17589e72a0364f6b8532d40aea593ad7
|
||||
#, python-format
|
||||
msgid "<a href=\"%(path)s\">Copyright</a> © %(copyright)s"
|
||||
msgstr "<a href=\"%(path)s\">Copyright</a> © %(copyright)s"
|
||||
|
||||
#: ../../_templates/page.html:133 0a35c662e6574da48f7ac5c6b2c82874
|
||||
#: ../../_templates/page.html:153 6603e5fc982d4b8b8ba3145dcf098be9
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Copyright © %(copyright)s, <a "
|
||||
|
|
@ -50,11 +54,11 @@ msgstr ""
|
|||
"href=\"https://justinmayer.com\">Justin Mayer</a>, Alexis Metaireau, and "
|
||||
"contributors"
|
||||
|
||||
#: ../../_templates/page.html:141 07b89372db484251bfcd3b54e0845bf0
|
||||
#: ../../_templates/page.html:161 757352d714c74c48ad540604822a210e
|
||||
#, python-format
|
||||
msgid "Last updated on %(last_updated)s"
|
||||
msgstr "最后更新于 %(last_updated)s"
|
||||
|
||||
#: ../../_templates/page.html:187 2eb9f1b479a7405290a91d8e1962f265
|
||||
#: ../../_templates/page.html:207 6b07f3b7330d47a3976e765b14da9ad1
|
||||
msgid "On this page"
|
||||
msgstr "本页目录"
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PELICAN 4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-11-07 16:25+0800\n"
|
||||
"PO-Revision-Date: 2024-06-27 19:00+0800\n"
|
||||
"POT-Creation-Date: 2026-02-02 10:32+0800\n"
|
||||
"PO-Revision-Date: 2026-02-02 10:32+0800\n"
|
||||
"Last-Translator: GeorgeHu <dhxxhch@163.com>\n"
|
||||
"Language: zh_CN\n"
|
||||
"Language-Team: zh_CN <LL@li.org>\n"
|
||||
|
|
@ -16,7 +16,7 @@ msgstr ""
|
|||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.16.0\n"
|
||||
"Generated-By: Babel 2.17.0\n"
|
||||
|
||||
#: ../../tips.rst:2 9c4618aaecd44b0d93537cb760e227fa
|
||||
msgid "Tips"
|
||||
|
|
@ -26,7 +26,7 @@ msgstr "小技巧"
|
|||
msgid "Here are some tips about Pelican that you might find useful."
|
||||
msgstr "以下是一些实用的小技巧。"
|
||||
|
||||
#: ../../tips.rst:7 ../../tips.rst:309 95bea35d0347495bb551fe9486bcd29d
|
||||
#: ../../tips.rst:7 ../../tips.rst:319 95bea35d0347495bb551fe9486bcd29d
|
||||
#: b64b7ed713b64f588ea7488c6d0b0441
|
||||
msgid "Custom 404 Pages"
|
||||
msgstr "自定义404页面"
|
||||
|
|
@ -373,11 +373,11 @@ msgstr ""
|
|||
"``\"publishconf.py\"`` 。"
|
||||
|
||||
#: ../../tips.rst:211 ../../tips.rst:216 ../../tips.rst:223 ../../tips.rst:227
|
||||
#: ../../tips.rst:231 ../../tips.rst:237 ../../tips.rst:243
|
||||
#: 073e18d8ae29406eb05040d4e3a9ae60 7d43e6cfb091410ebec7464da05b61b4
|
||||
#: 8837cc8935f148fb80f05cc5d3d53629 b2da1f7640f948039230cd835c49accd
|
||||
#: bfe3d052cdc443bb81fed82e77acf3c1 c93816e00a254ef69c69f05833e8762b
|
||||
#: ee35302c7e034070af1d234ab919c32a
|
||||
#: ../../tips.rst:231 ../../tips.rst:237 ../../tips.rst:243 ../../tips.rst:249
|
||||
#: 073e18d8ae29406eb05040d4e3a9ae60 6932c9139d4f4da7a34601a9d78ee622
|
||||
#: 7d43e6cfb091410ebec7464da05b61b4 8837cc8935f148fb80f05cc5d3d53629
|
||||
#: b2da1f7640f948039230cd835c49accd bfe3d052cdc443bb81fed82e77acf3c1
|
||||
#: c93816e00a254ef69c69f05833e8762b ee35302c7e034070af1d234ab919c32a
|
||||
msgid "string"
|
||||
msgstr "string"
|
||||
|
||||
|
|
@ -386,11 +386,12 @@ msgid "``requirements``"
|
|||
msgstr "``requirements``"
|
||||
|
||||
#: ../../tips.rst:216 ../../tips.rst:223 ../../tips.rst:227 ../../tips.rst:231
|
||||
#: ../../tips.rst:237 ../../tips.rst:243 ../../tips.rst:249
|
||||
#: 197d6ee11fce4a50996a0c458cfdbdad 2086d667b9b1475cb0f002924cdfde12
|
||||
#: 25e940621f5b48c9af487d898d7f93cf 5664232c9fdd46c7b8278b8ecef8e3b1
|
||||
#: ../../tips.rst:237 ../../tips.rst:243 ../../tips.rst:249 ../../tips.rst:255
|
||||
#: ../../tips.rst:261 197d6ee11fce4a50996a0c458cfdbdad
|
||||
#: 2086d667b9b1475cb0f002924cdfde12 25e940621f5b48c9af487d898d7f93cf
|
||||
#: 3052432fbf5d420d8f6adbadb908e6f0 5664232c9fdd46c7b8278b8ecef8e3b1
|
||||
#: 6693126a0da74c61b67e14ca8e535ec3 7f8a93a2048140748fa73537bfae2a54
|
||||
#: 85fd40a29f31490bb23b20f05e574aaa
|
||||
#: 85fd40a29f31490bb23b20f05e574aaa 9d02d6e4689b4b55bdf832e18b0ed4bb
|
||||
msgid "No"
|
||||
msgstr "否"
|
||||
|
||||
|
|
@ -429,46 +430,60 @@ msgid ""
|
|||
"``\"https://github.com/seanh/sidecar.git\"``"
|
||||
msgstr "要使用的自定义主题的GitHub仓库URL,例如: ``\"https://github.com/seanh/sidecar.git\"``"
|
||||
|
||||
#: ../../tips.rst:227 d94f331173334fb2a84b1caadffb72df
|
||||
#: ../../tips.rst:227 ../../tips.rst:231 919c0e36e8ff40bcbcc4480081b49ce5
|
||||
#: d94f331173334fb2a84b1caadffb72df
|
||||
msgid "``\"\"``"
|
||||
msgstr "``\"\"``"
|
||||
|
||||
#: ../../tips.rst:231 44ceb2743481486b95c1c739d543f15d
|
||||
#: ../../tips.rst:231 921a2ae610a84349a5654e204ba6b034
|
||||
msgid "``theme-checkout``"
|
||||
msgstr "``theme-checkout``"
|
||||
|
||||
#: ../../tips.rst:231 7815b328b5f94ca496107881f5bb8aab
|
||||
msgid ""
|
||||
"Git ref (branch, tag or commit) of the theme repo to checkout. This can "
|
||||
"be used to pin the version of your theme. If not specified defaults to "
|
||||
"the theme repo's default branch."
|
||||
msgstr ""
|
||||
"主题仓库要checkout的Git引用 (branch, tag 或 commit)。这可以用于固定主题的版本。若未指定,"
|
||||
"使用仓库的默认branch。"
|
||||
|
||||
#: ../../tips.rst:237 44ceb2743481486b95c1c739d543f15d
|
||||
msgid "``python``"
|
||||
msgstr "``python``"
|
||||
|
||||
#: ../../tips.rst:231 4b5cddab44d24c7c8560e16991b784c7
|
||||
#: ../../tips.rst:237 4b5cddab44d24c7c8560e16991b784c7
|
||||
msgid ""
|
||||
"The version of Python to use to build the site, for example: ``\"3.12\"``"
|
||||
" (to use the most recent version of Python 3.12, this is faster) or "
|
||||
"``\"3.12.1\"`` (to use an exact version, slower)"
|
||||
msgstr "构建站点时使用的Python版本,例如: ``\"3.12\"`` 或 ``\"3.12.1\"``"
|
||||
|
||||
#: ../../tips.rst:231 919c0e36e8ff40bcbcc4480081b49ce5
|
||||
#: ../../tips.rst:237 919c0e36e8ff40bcbcc4480081b49ce5
|
||||
msgid "``\"3.12\"``"
|
||||
msgstr "``\"3.12\"``"
|
||||
|
||||
#: ../../tips.rst:237 842af56c539f4a74a97c7a5b1525eb35
|
||||
#: ../../tips.rst:243 842af56c539f4a74a97c7a5b1525eb35
|
||||
msgid "``siteurl``"
|
||||
msgstr "``siteurl``"
|
||||
|
||||
#: ../../tips.rst:237 7fc0777d6e174d6f8d757926a61aa3c8
|
||||
#: ../../tips.rst:243 7fc0777d6e174d6f8d757926a61aa3c8
|
||||
msgid ""
|
||||
"The base URL of your web site (Pelican's ``SITEURL`` setting). If not "
|
||||
"passed this will default to the URL of your GitHub Pages site, which is "
|
||||
"correct in most cases."
|
||||
msgstr "站点的基URL,会用于配置项 ``SITEURL`` 。若未指定,默认值为GitHub Pages站点的URL,这适用于大部分情况。"
|
||||
|
||||
#: ../../tips.rst:237 ../../tips.rst:243 082f65333e224d71817b82b1e4f515c4
|
||||
#: ../../tips.rst:243 ../../tips.rst:249 082f65333e224d71817b82b1e4f515c4
|
||||
#: 3d786e828a4745db849bdb8f47738db8
|
||||
msgid "The URL of your GitHub Pages site."
|
||||
msgstr "GitHub Pages站点的URL"
|
||||
|
||||
#: ../../tips.rst:243 e5adb69f985547b7b3cc2bd3f31d4cc3
|
||||
#: ../../tips.rst:249 e5adb69f985547b7b3cc2bd3f31d4cc3
|
||||
msgid "``feed_domain``"
|
||||
msgstr "``feed_domain``"
|
||||
|
||||
#: ../../tips.rst:243 c88f037c9f1f4148bef6347228257f7d
|
||||
#: ../../tips.rst:249 c88f037c9f1f4148bef6347228257f7d
|
||||
msgid ""
|
||||
"The domain to be prepended to feed URLs (Pelican's ``FEED_DOMAIN`` "
|
||||
"setting). If not passed this will default to the URL of your GitHub Pages"
|
||||
|
|
@ -477,72 +492,89 @@ msgstr ""
|
|||
"订阅源URL前要附加的域名,会用于配置项 ``FEED_DOMAIN`` 。若未指定,默认值为GitHub "
|
||||
"Pages站点的URL,这适用于大部分情况。"
|
||||
|
||||
#: ../../tips.rst:249 358c5aa434cd4ad09beab02df88413d5
|
||||
#: ../../tips.rst:255 358c5aa434cd4ad09beab02df88413d5
|
||||
msgid "``deploy``"
|
||||
msgstr "``deploy``"
|
||||
|
||||
#: ../../tips.rst:249 b8748aeace5a448d9382e225be98f90c
|
||||
#: ../../tips.rst:255 b8748aeace5a448d9382e225be98f90c
|
||||
msgid ""
|
||||
"This is used to determine whether you will deploy the site or not to "
|
||||
"GitHub Pages. This is most useful if you want to test a change to your "
|
||||
"website in a pull request before deploying those change."
|
||||
msgstr "此项配置用于表示是否要将站点部署至GitHub Pages。当对站点做了更改,并且在正式部署前进行测试,就可以用到此项。"
|
||||
|
||||
#: ../../tips.rst:249 034006b9b71b4cb486f230b8aad873ce
|
||||
#: ../../tips.rst:255 ../../tips.rst:261 034006b9b71b4cb486f230b8aad873ce
|
||||
msgid "bool"
|
||||
msgstr "bool"
|
||||
|
||||
#: ../../tips.rst:249 078ac613a8b74703af98c75bb5a007c1
|
||||
#: ../../tips.rst:255 078ac613a8b74703af98c75bb5a007c1
|
||||
msgid "``true``"
|
||||
msgstr "``true``"
|
||||
|
||||
#: ../../tips.rst:257 e63cf881e3204be8b52ee5d8635ba4cf
|
||||
#: ../../tips.rst:261 842af56c539f4a74a97c7a5b1525eb35
|
||||
msgid "``stork``"
|
||||
msgstr "``stork``"
|
||||
|
||||
#: ../../tips.rst:261 b8748aeace5a448d9382e225be98f90c
|
||||
msgid ""
|
||||
"This is used to determine whether Stork will be installed on the runner "
|
||||
"to be able to build a site with Stork search enabled"
|
||||
msgstr ""
|
||||
"此配置项用于指定是否要在runner中安装Stork搜索。"
|
||||
|
||||
#: ../../tips.rst:261 358c5aa434cd4ad09beab02df88413d5
|
||||
msgid "``false``"
|
||||
msgstr "``false``"
|
||||
|
||||
#: ../../tips.rst:267 e63cf881e3204be8b52ee5d8635ba4cf
|
||||
msgid "Testing Your Build in a GitHub Pull Request"
|
||||
msgstr "在Github拉取请求时进行测试"
|
||||
|
||||
#: ../../tips.rst:259 a2f6bd3420eb46a08f54efda35a6eaf4
|
||||
#: ../../tips.rst:269 a2f6bd3420eb46a08f54efda35a6eaf4
|
||||
msgid ""
|
||||
"If you want to test your build in a pull request before deploying to "
|
||||
"GitHub, your workflow might look something like this:"
|
||||
msgstr "如果想在正式部署到 GitHub 前在PR中进行测试,下面是一个可用的 workflow 示例"
|
||||
|
||||
#: ../../tips.rst:288 84393693279741efa82c5ee6b27cbd28
|
||||
#: ../../tips.rst:298 84393693279741efa82c5ee6b27cbd28
|
||||
msgid ""
|
||||
"The ``on`` section of the workflow defines the events that will trigger "
|
||||
"the workflow. In this example, the workflow will run on pushes to the "
|
||||
"main branch, pull requests to the main branch, and manual runs of the "
|
||||
"workflow."
|
||||
msgstr "工作流的 ``on`` 部分定义了工作流的触发器。在此示例中,工作流将在main分支收到push、有PR提起到主分支以及"
|
||||
"手动运行工作流时执行。"
|
||||
msgstr "工作流的 ``on`` 部分定义了工作流的触发器。在此示例中,工作流将在main分支收到push、有PR提起到主分支以及手动运行工作流时执行。"
|
||||
|
||||
#: ../../tips.rst:290 cd3c13b2af974a32aa4291d07fc11e9c
|
||||
#: ../../tips.rst:300 cd3c13b2af974a32aa4291d07fc11e9c
|
||||
msgid ""
|
||||
"``workflow_dispatch`` defines the deploy boolean to be true by default. "
|
||||
"This means that if you run the workflow manually, it will deploy the "
|
||||
"site."
|
||||
msgstr "``workflow_dispatch`` 将 deploy 的默认值设为 true。也就是说当手动运行工作流时,更改的内容就会正式部署。"
|
||||
|
||||
#: ../../tips.rst:292 5402cd211d5b4aa8a244c916bb381a5b
|
||||
#: ../../tips.rst:302 5402cd211d5b4aa8a244c916bb381a5b
|
||||
msgid ""
|
||||
"The ``deploy`` input for the job is using a set of standard GitHub "
|
||||
"workflow variables to control when ``deploy`` will either be true or "
|
||||
"false (you can customize this to your needs)."
|
||||
msgstr "job中的 ``deploy`` 使用了一些 GitHub workflow 变量来计算 ``deploy`` 值为 true 还是 false(您可以根据需要自定义)。"
|
||||
msgstr ""
|
||||
"job中的 ``deploy`` 使用了一些 GitHub workflow 变量来计算 ``deploy`` 值为 true 还是 "
|
||||
"false(您可以根据需要自定义)。"
|
||||
|
||||
#: ../../tips.rst:294 d084908e3a0749f0b802b43626cfe2c4
|
||||
#: ../../tips.rst:304 d084908e3a0749f0b802b43626cfe2c4
|
||||
msgid ""
|
||||
"In this example, the ``deploy`` will be true if the event is a push to "
|
||||
"the main branch (or merging into main from a PR) or a manual run of the "
|
||||
"workflow. If the event is a pull request, the ``deploy`` will be false "
|
||||
"and it will only build an artifact for the site."
|
||||
msgstr "在此示例中,如果触发事件是推送到主分支(或从 PR 合并到主分支)或手动运行工作流,则 deploy 将为 true;"
|
||||
"如果触发事件只是Pull Request,则 ``deploy`` 将为 false,并且此时只会为站点构建一个artifact。"
|
||||
msgstr ""
|
||||
"在此示例中,如果触发事件是推送到主分支(或从 PR 合并到主分支)或手动运行工作流,则 deploy 将为 true;如果触发事件只是Pull "
|
||||
"Request,则 ``deploy`` 将为 false,并且此时只会为站点构建一个artifact。"
|
||||
|
||||
#: ../../tips.rst:297 85e70fc3faa04208979f7bbe92b025ef
|
||||
#: ../../tips.rst:307 85e70fc3faa04208979f7bbe92b025ef
|
||||
msgid "\"Insecure content\" warnings from browsers"
|
||||
msgstr "浏览器报“不安全的内容(Insecure content)”警告"
|
||||
|
||||
#: ../../tips.rst:299 34f7075cf31f416da2aeb529c616d97d
|
||||
#: ../../tips.rst:309 34f7075cf31f416da2aeb529c616d97d
|
||||
msgid ""
|
||||
"If your site uses ``https://`` and is broken because the browser is "
|
||||
"blocking network requests (for example for CSS files) due to \"insecure "
|
||||
|
|
@ -553,7 +585,7 @@ msgstr ""
|
|||
"时,可能会损坏,无法正常显示,这是由于浏览器阻拦了一些对“不安全内容”的网络请求。可能的原因之一是GitHub Pages给你的站点生成了 "
|
||||
"``http://`` URL。"
|
||||
|
||||
#: ../../tips.rst:303 47271df82577424c8e2c31a9e76a553a
|
||||
#: ../../tips.rst:313 47271df82577424c8e2c31a9e76a553a
|
||||
msgid ""
|
||||
"To fix this go into your site repo's settings and enable the **Enforce "
|
||||
"HTTPS** setting: go to **Settings → Pages** and check **Enforce HTTPS**. "
|
||||
|
|
@ -564,7 +596,7 @@ msgstr ""
|
|||
"**Enforce HTTPS** ,接着再重新执行工作流以重新部署站点。也可以尝试通过配置 ``siteurl`` 与 "
|
||||
"``feed_domain`` 解决问题。"
|
||||
|
||||
#: ../../tips.rst:311 e69189ef4a8440fb8940d8012b4f19d6
|
||||
#: ../../tips.rst:321 e69189ef4a8440fb8940d8012b4f19d6
|
||||
msgid ""
|
||||
"GitHub Pages will display the custom 404 page described above, as noted "
|
||||
"in the relevant `GitHub docs "
|
||||
|
|
@ -573,11 +605,11 @@ msgstr ""
|
|||
"如果按前述进行配置,GitHub Pages是能够正确显示自定义的404页面的,相关内容在 `GitHub的文档中 "
|
||||
"<https://help.github.com/articles/custom-404-pages/>`_ 也有提到。"
|
||||
|
||||
#: ../../tips.rst:315 1b8c2457f44a4d61a033363830b8bd90
|
||||
#: ../../tips.rst:325 1b8c2457f44a4d61a033363830b8bd90
|
||||
msgid "Update your site on each commit"
|
||||
msgstr "在每次commit后都更新站点"
|
||||
|
||||
#: ../../tips.rst:317 476dbdb670924c02a962e78d6a7854c1
|
||||
#: ../../tips.rst:327 476dbdb670924c02a962e78d6a7854c1
|
||||
msgid ""
|
||||
"To automatically update your Pelican site on each commit, you can create "
|
||||
"a post-commit hook. For example, you can add the following to "
|
||||
|
|
@ -586,11 +618,11 @@ msgstr ""
|
|||
"要想在每次commit后自动更新Pelican站点,你可以创建一个post-commit钩子。例如,可以将下面的内容保存为 "
|
||||
"``.git/hooks/post-commit`` :"
|
||||
|
||||
#: ../../tips.rst:324 36dc5f05eaf84573acada36c59d8d2fc
|
||||
#: ../../tips.rst:334 36dc5f05eaf84573acada36c59d8d2fc
|
||||
msgid "Copy static files to the root of your site"
|
||||
msgstr "将静态文件拷贝到站点根目录"
|
||||
|
||||
#: ../../tips.rst:326 4a0722ad68e944ee80e6378259cc1dd6
|
||||
#: ../../tips.rst:336 4a0722ad68e944ee80e6378259cc1dd6
|
||||
msgid ""
|
||||
"To use a `custom domain <https://help.github.com/articles/setting-up-a"
|
||||
"-custom-domain-with-pages>`_ with GitHub Pages, you need to put the "
|
||||
|
|
@ -605,11 +637,11 @@ msgstr ""
|
|||
")添加到站点根目录的 ``CNAME`` 文件中。为此,请创建 ``content/extra/`` 目录,并在里面添加一个 ``CNAME`` "
|
||||
"文件。然后使用Pelican的 ``STATIC_PATHS`` 来告诉Pelican将此文件复制到输出目录:"
|
||||
|
||||
#: ../../tips.rst:337 8ad906848762400d9e2462034d151a16
|
||||
#: ../../tips.rst:347 8ad906848762400d9e2462034d151a16
|
||||
msgid "Note: use forward slashes, ``/``, even on Windows."
|
||||
msgstr "请注意:务必使用正斜杠 ``/`` ,在Windows上也是。"
|
||||
|
||||
#: ../../tips.rst:339 7b109f4944064382babc9158567c8e82
|
||||
#: ../../tips.rst:349 7b109f4944064382babc9158567c8e82
|
||||
msgid ""
|
||||
"You can also use the ``EXTRA_PATH_METADATA`` mechanism to place a "
|
||||
"``favicon.ico`` or ``robots.txt`` at the root of any site."
|
||||
|
|
@ -617,17 +649,17 @@ msgstr ""
|
|||
"利用 ``EXTRA_PATH_METADATA`` 机制,你可以将 ``favicon.ico`` 或 ``robots.txt`` "
|
||||
"也拷贝到站点的根目录下。"
|
||||
|
||||
#: ../../tips.rst:343 678eea0644b5400496ad9173d05368d5
|
||||
#: ../../tips.rst:353 678eea0644b5400496ad9173d05368d5
|
||||
msgid "How to add YouTube or Vimeo Videos"
|
||||
msgstr "如何添加YouTube或Vimeo视频"
|
||||
|
||||
#: ../../tips.rst:345 ca57b327dd6b432d82cdc91193bde6bb
|
||||
#: ../../tips.rst:355 ca57b327dd6b432d82cdc91193bde6bb
|
||||
msgid ""
|
||||
"The easiest way is to paste the embed code of the video from these sites "
|
||||
"directly into your source content."
|
||||
msgstr "最简单的方法是将这些网站的视频嵌入代码直接粘贴到您的源内容文件中。"
|
||||
|
||||
#: ../../tips.rst:348 0a4f27e2edbe494ab52f73595646986e
|
||||
#: ../../tips.rst:358 0a4f27e2edbe494ab52f73595646986e
|
||||
msgid ""
|
||||
"Alternatively, you can also use Pelican plugins like ``liquid_tags``, "
|
||||
"``pelican_youtube``, or ``pelican_vimeo`` to embed videos in your "
|
||||
|
|
@ -636,7 +668,7 @@ msgstr ""
|
|||
"或者,您还可以使用例如 ``liquid_tags`` 、``pelican_youtube`` 或 ``pelican_vimeo`` "
|
||||
"等Pelican插件将视频嵌入。"
|
||||
|
||||
#: ../../tips.rst:351 e73517b72da347738421784b776b1f1c
|
||||
#: ../../tips.rst:361 e73517b72da347738421784b776b1f1c
|
||||
msgid ""
|
||||
"Moreover, markup languages like reST and Markdown have plugins that let "
|
||||
"you embed videos in the markup. You can use `reST video directive "
|
||||
|
|
@ -647,31 +679,31 @@ msgstr ""
|
|||
"<https://gist.github.com/dbrgn/2922648>`_ 或者 `Markdown的mdx_video插件 "
|
||||
"<https://github.com/italomaia/mdx-video>`_ 。"
|
||||
|
||||
#: ../../tips.rst:358 b9d27cda716048b2ab7c13646d7faf09
|
||||
#: ../../tips.rst:368 b9d27cda716048b2ab7c13646d7faf09
|
||||
msgid "Develop Locally Using SSL"
|
||||
msgstr "在本地使用SSL进行开发"
|
||||
|
||||
#: ../../tips.rst:360 50df9ec072aa47eabbae132fd8f5cb68
|
||||
#: ../../tips.rst:370 50df9ec072aa47eabbae132fd8f5cb68
|
||||
msgid "Here's how you can set up your local pelican server to support SSL."
|
||||
msgstr "以下描述了如何在本地Pelican服务器上配置SSL。"
|
||||
|
||||
#: ../../tips.rst:362 9b5045375a874c4d9c29f7109f05c539
|
||||
#: ../../tips.rst:372 9b5045375a874c4d9c29f7109f05c539
|
||||
msgid ""
|
||||
"First, create a self-signed certificate and key using ``openssl`` (this "
|
||||
"creates ``cert.pem`` and ``key.pem``)::"
|
||||
msgstr "首先,通过 ``openssl`` 创建自签名的证书和密钥,这会生成 ``cert.pem`` 和 ``key.pem`` 文件:"
|
||||
|
||||
#: ../../tips.rst:366 2f1cfa536fc540f69d671f8a118769d7
|
||||
#: ../../tips.rst:376 2f1cfa536fc540f69d671f8a118769d7
|
||||
msgid ""
|
||||
"And use this command to launch the server (the server starts within your "
|
||||
"``output`` directory)::"
|
||||
msgstr "接着使用下面的命令来开启服务器(此服务器会在 ``output`` 目录下开启):"
|
||||
|
||||
#: ../../tips.rst:370 029ea2b0e4fe4b0f814158ae33e3a8ff
|
||||
#: ../../tips.rst:380 029ea2b0e4fe4b0f814158ae33e3a8ff
|
||||
msgid "If you are using ``develop-server.sh``, add this to the top::"
|
||||
msgstr "如果你使用的是 ``develop-server.sh`` 脚本,在脚本的开头添加:"
|
||||
|
||||
#: ../../tips.rst:375 c2784fdd9fdb433799d57f903d0e49d8
|
||||
#: ../../tips.rst:385 c2784fdd9fdb433799d57f903d0e49d8
|
||||
msgid "and modify the ``pelican.server`` line as follows::"
|
||||
msgstr "然后修改按照下述修改 ``pelican.server`` 一行:"
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,11 @@ Please note that while we do our best to review and maintain these plugins,
|
|||
they are submitted by the Pelican community and thus may have varying levels of
|
||||
support and interoperability.
|
||||
|
||||
Community plugins can also be found on PyPI tagged with "`Framework ::
|
||||
Pelican :: Plugins`_".
|
||||
|
||||
.. _Framework :: Pelican :: Plugins: https://pypi.org/search/?q=&o=-created&c=Framework+%3A%3A+Pelican+%3A%3A+Plugins
|
||||
|
||||
How to create plugins
|
||||
=====================
|
||||
|
||||
|
|
@ -112,10 +117,10 @@ and have a folder structure as follows::
|
|||
|
||||
myplugin
|
||||
├── pelican
|
||||
│ └── plugins
|
||||
│ └── myplugin
|
||||
│ ├── __init__.py
|
||||
│ └── ...
|
||||
│ └── plugins
|
||||
│ └── myplugin
|
||||
│ ├── __init__.py
|
||||
│ └── ...
|
||||
├── ...
|
||||
└── setup.py
|
||||
|
||||
|
|
@ -146,7 +151,9 @@ finalized pelican object invoked after
|
|||
generator_init generator invoked in the Generator.__init__
|
||||
all_generators_finalized generators invoked after all the generators are executed and before writing output
|
||||
readers_init readers invoked in the Readers.__init__
|
||||
article_generator_context article_generator, metadata
|
||||
article_generator_context article_generator, metadata invoked after the content and metadata for the article has been generated;
|
||||
use if you need to adjust the article metadata before it gets used by
|
||||
Pelican.
|
||||
article_generator_preread article_generator invoked before a article is read in ArticlesGenerator.generate_context;
|
||||
use if code needs to do something before every article is parsed
|
||||
article_generator_init article_generator invoked in the ArticlesGenerator.__init__
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ Basic settings
|
|||
|
||||
.. data:: DEFAULT_CATEGORY
|
||||
|
||||
The default category to fall back on. The default is ``'misc'``.
|
||||
The default category to fall back on. The default is ``"misc"``.
|
||||
|
||||
.. data:: DISPLAY_PAGES_ON_MENU
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ Basic settings
|
|||
A dictionary of custom Jinja2 environment variables you want to use. This
|
||||
also includes a list of extensions you may want to include. See `Jinja
|
||||
Environment documentation`_. The default is
|
||||
``{'extensions': [], 'trim_blocks': True, 'lstrip_blocks': True}``.
|
||||
``{"extensions": [], "trim_blocks": True, "lstrip_blocks": True}``.
|
||||
|
||||
.. data:: JINJA_FILTERS
|
||||
|
||||
|
|
@ -114,10 +114,10 @@ Basic settings
|
|||
Example::
|
||||
|
||||
import sys
|
||||
sys.path.append('to/your/path')
|
||||
sys.path.append("to/your/path")
|
||||
|
||||
from custom_filter import urlencode_filter
|
||||
JINJA_FILTERS = {'urlencode': urlencode_filter}
|
||||
JINJA_FILTERS = {"urlencode": urlencode_filter}
|
||||
|
||||
See: `Jinja custom filters documentation`_. The default is ``{}``.
|
||||
|
||||
|
|
@ -141,7 +141,7 @@ Basic settings
|
|||
|
||||
Example::
|
||||
|
||||
LOG_FILTER = [(logging.WARN, 'TAG_SAVE_AS is set to False')]
|
||||
LOG_FILTER = [(logging.WARN, "TAG_SAVE_AS is set to False")]
|
||||
|
||||
The default is ``[]``.
|
||||
|
||||
|
|
@ -152,11 +152,11 @@ Basic settings
|
|||
|
||||
For example, to avoid processing .html files, set::
|
||||
|
||||
READERS = {'html': None}
|
||||
READERS = {"html": None}
|
||||
|
||||
To add a custom reader for the ``foo`` extension, set::
|
||||
|
||||
READERS = {'foo': FooReader}
|
||||
READERS = {"foo": FooReader}
|
||||
|
||||
The default is ``{}``.
|
||||
|
||||
|
|
@ -164,14 +164,14 @@ Basic settings
|
|||
|
||||
A list of Unix glob patterns. Files and directories matching any of these patterns
|
||||
or any of the commonly hidden files and directories set by ``watchfiles.DefaultFilter``
|
||||
will be ignored by the processor. For example, the default ``['**/.*']`` will
|
||||
ignore "hidden" files and directories, and ``['__pycache__']`` would ignore
|
||||
will be ignored by the processor. For example, the default ``["**/.*"]`` will
|
||||
ignore "hidden" files and directories, and ``["__pycache__"]`` would ignore
|
||||
Python 3's bytecode caches.
|
||||
|
||||
For a full list of the commonly hidden files set by ``watchfiles.DefaultFilter``,
|
||||
please refer to the `watchfiles documentation`_.
|
||||
|
||||
The default is ``['**/.*']``.
|
||||
The default is ``["**/.*"]``.
|
||||
|
||||
.. data:: MARKDOWN
|
||||
|
||||
|
|
@ -184,12 +184,12 @@ Basic settings
|
|||
The default is::
|
||||
|
||||
MARKDOWN = {
|
||||
'extension_configs': {
|
||||
'markdown.extensions.codehilite': {'css_class': 'highlight'},
|
||||
'markdown.extensions.extra': {},
|
||||
'markdown.extensions.meta': {},
|
||||
"extension_configs": {
|
||||
"markdown.extensions.codehilite": {"css_class": "highlight"},
|
||||
"markdown.extensions.extra": {},
|
||||
"markdown.extensions.meta": {},
|
||||
},
|
||||
'output_format': 'html5',
|
||||
"output_format": "html5",
|
||||
}
|
||||
|
||||
.. Note::
|
||||
|
|
@ -201,18 +201,18 @@ Basic settings
|
|||
Where to output the generated files. This should correspond to your web
|
||||
server's virtual host root directory.
|
||||
|
||||
The default is ``'output'``.
|
||||
The default is ``"output"``.
|
||||
|
||||
.. data:: PATH
|
||||
|
||||
Path to content directory to be processed by Pelican. If undefined, and
|
||||
content path is not specified via an argument to the ``pelican`` command,
|
||||
Pelican will default to ``'.'``, the current working directory.
|
||||
Pelican will default to ``"."``, the current working directory.
|
||||
|
||||
.. data:: PAGE_PATHS
|
||||
|
||||
A list of directories and files to look at for pages, relative to ``PATH``.
|
||||
The default is ``['pages']``.
|
||||
The default is ``["pages"]``.
|
||||
|
||||
.. data:: PAGE_EXCLUDES
|
||||
|
||||
|
|
@ -222,7 +222,7 @@ Basic settings
|
|||
.. data:: ARTICLE_PATHS
|
||||
|
||||
A list of directories and files to look at for articles, relative to
|
||||
``PATH``. The default is ``['']``.
|
||||
``PATH``. The default is ``[""]``.
|
||||
|
||||
.. data:: ARTICLE_EXCLUDES
|
||||
|
||||
|
|
@ -239,7 +239,7 @@ Basic settings
|
|||
|
||||
Controls the extension that will be used by the SourcesGenerator. Defaults
|
||||
to ``.text``. If not a valid string the default value will be used. The
|
||||
default is ``'.text'``.
|
||||
default is ``".text"``.
|
||||
|
||||
.. data:: PLUGINS
|
||||
|
||||
|
|
@ -252,7 +252,7 @@ Basic settings
|
|||
|
||||
.. data:: SITENAME
|
||||
|
||||
Your site's name. The default is ``'A Pelican Blog'``.
|
||||
Your site's name. The default is ``"A Pelican Blog"``.
|
||||
|
||||
.. data:: SITEURL
|
||||
|
||||
|
|
@ -261,9 +261,9 @@ Basic settings
|
|||
properly-formed URLs. If your site is available via HTTPS, this setting
|
||||
should begin with ``https://`` — otherwise use ``http://``. Then append your
|
||||
domain, with no trailing slash at the end. Example: ``SITEURL =
|
||||
'https://example.com'``
|
||||
"https://example.com"``
|
||||
|
||||
The default is ``''``, the blank string.
|
||||
The default is ``""``, the blank string.
|
||||
|
||||
.. data:: STATIC_PATHS
|
||||
|
||||
|
|
@ -272,7 +272,7 @@ Basic settings
|
|||
modification. Articles, pages, and other content source files will normally
|
||||
be skipped, so it is safe for a directory to appear both here and in
|
||||
``PAGE_PATHS`` or ``ARTICLE_PATHS``. Pelican's default settings include the
|
||||
"images" directory here. The default is ``['images']``.
|
||||
"images" directory here. The default is ``["images"]``.
|
||||
|
||||
.. data:: STATIC_EXCLUDES
|
||||
|
||||
|
|
@ -318,8 +318,8 @@ Basic settings
|
|||
|
||||
.. data:: TYPOGRIFY_OMIT_FILTERS
|
||||
|
||||
A list of Typogrify filters to skip. Allowed values are: ``'amp'``,
|
||||
``'smartypants'``, ``'caps'``, ``'initial_quotes'``, ``'widont'``. By
|
||||
A list of Typogrify filters to skip. Allowed values are: ``"amp"``,
|
||||
``"smartypants"``, ``"caps"``, ``"initial_quotes"``, ``"widont"``. By
|
||||
default, no filter is omitted (in other words, all filters get applied). This
|
||||
setting requires that Typogrify version 2.1.0 or later is installed. The
|
||||
default is ``[]``.
|
||||
|
|
@ -333,7 +333,7 @@ Basic settings
|
|||
``oldschool`` setting renders both en-dashes and em-dashes when it sees two
|
||||
(``--``) and three (``---``) hyphen characters, respectively. The
|
||||
``oldschool_inverted`` setting turns two hyphens into an em-dash and three
|
||||
hyphens into an en-dash. The default is ``'default'``.
|
||||
hyphens into an en-dash. The default is ``"default"``.
|
||||
|
||||
.. data:: SUMMARY_MAX_LENGTH
|
||||
|
||||
|
|
@ -354,7 +354,7 @@ Basic settings
|
|||
|
||||
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 suffix.
|
||||
The default is ``'…'``.
|
||||
The default is ``"…"``.
|
||||
|
||||
.. data:: WITH_FUTURE_DATES
|
||||
|
||||
|
|
@ -369,7 +369,7 @@ Basic settings
|
|||
``filename``, in ``{}`` or ``||``. Identifier between ``{`` and ``}`` goes
|
||||
into the ``what`` capturing group. For details see
|
||||
:ref:`ref-linking-to-internal-content`. The default is
|
||||
``'[{|](?P<what>.*?)[|}]'``.
|
||||
``"[{|](?P<what>.*?)[|}]"``.
|
||||
|
||||
.. data:: PYGMENTS_RST_OPTIONS
|
||||
|
||||
|
|
@ -385,13 +385,13 @@ Basic settings
|
|||
|
||||
.. data:: CONTENT_CACHING_LAYER
|
||||
|
||||
If set to ``'reader'``, save only the raw content and metadata returned by
|
||||
readers. If set to ``'generator'``, save processed content objects. The
|
||||
default is ``'reader'``.
|
||||
If set to ``"reader"``, save only the raw content and metadata returned by
|
||||
readers. If set to ``"generator"``, save processed content objects. The
|
||||
default is ``"reader"``.
|
||||
|
||||
.. data:: CACHE_PATH
|
||||
|
||||
Directory in which to store cache files. The default is ``'cache'``.
|
||||
Directory in which to store cache files. The default is ``"cache"``.
|
||||
|
||||
.. data:: GZIP_CACHE
|
||||
|
||||
|
|
@ -402,12 +402,12 @@ Basic settings
|
|||
|
||||
Controls how files are checked for modifications.
|
||||
|
||||
- If set to ``'mtime'``, the modification time of the file is
|
||||
- If set to ``"mtime"``, the modification time of the file is
|
||||
checked.
|
||||
- If set to a name of a function provided by the ``hashlib``
|
||||
module, e.g. ``'md5'``, the file hash is checked.
|
||||
module, e.g. ``"md5"``, the file hash is checked.
|
||||
|
||||
The default is ``'mtime'``.
|
||||
The default is ``"mtime"``.
|
||||
|
||||
.. data:: LOAD_CONTENT_CACHE
|
||||
|
||||
|
|
@ -416,7 +416,7 @@ Basic settings
|
|||
.. data:: FORMATTED_FIELDS
|
||||
|
||||
A list of metadata fields containing reST/Markdown content to be parsed and
|
||||
translated to HTML. The default is ``['summary']``.
|
||||
translated to HTML. The default is ``["summary"]``.
|
||||
|
||||
.. data:: PORT
|
||||
|
||||
|
|
@ -425,7 +425,7 @@ Basic settings
|
|||
|
||||
.. data:: BIND
|
||||
|
||||
The IP to which to bind the HTTP server. The default is ``'127.0.0.1'``.
|
||||
The IP to which to bind the HTTP server. The default is ``"127.0.0.1"``.
|
||||
|
||||
.. _url-settings:
|
||||
|
||||
|
|
@ -458,8 +458,8 @@ If you don't want that flexibility and instead prefer that your generated
|
|||
output paths mirror your source content's filesystem path hierarchy, try the
|
||||
following settings::
|
||||
|
||||
PATH_METADATA = r'(?P<path_no_ext>.*)\..*'
|
||||
ARTICLE_URL = ARTICLE_SAVE_AS = PAGE_URL = PAGE_SAVE_AS = '{path_no_ext}.html'
|
||||
PATH_METADATA = r"(?P<path_no_ext>.*)\..*"
|
||||
ARTICLE_URL = ARTICLE_SAVE_AS = PAGE_URL = PAGE_SAVE_AS = "{path_no_ext}.html"
|
||||
|
||||
Otherwise, you can use a variety of file metadata attributes within URL-related
|
||||
settings:
|
||||
|
|
@ -472,10 +472,10 @@ settings:
|
|||
|
||||
Example usage::
|
||||
|
||||
ARTICLE_URL = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/'
|
||||
ARTICLE_SAVE_AS = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/index.html'
|
||||
PAGE_URL = 'pages/{slug}/'
|
||||
PAGE_SAVE_AS = 'pages/{slug}/index.html'
|
||||
ARTICLE_URL = "posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/"
|
||||
ARTICLE_SAVE_AS = "posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/index.html"
|
||||
PAGE_URL = "pages/{slug}/"
|
||||
PAGE_SAVE_AS = "pages/{slug}/index.html"
|
||||
|
||||
This would save your articles into something like
|
||||
``/posts/2011/Aug/07/sample-post/index.html``, save your pages into
|
||||
|
|
@ -499,111 +499,111 @@ This would save your articles into something like
|
|||
|
||||
.. data:: ARTICLE_URL
|
||||
|
||||
The URL to refer to an article. The default is ``'{slug}.html'``.
|
||||
The URL to refer to an article. The default is ``"{slug}.html"``.
|
||||
|
||||
.. data:: ARTICLE_SAVE_AS
|
||||
|
||||
The place where we will save an article. The default is ``'{slug}.html'``.
|
||||
The place where we will save an article. The default is ``"{slug}.html"``.
|
||||
|
||||
.. data:: ARTICLE_LANG_URL
|
||||
|
||||
The URL to refer to an article which doesn't use the default language.
|
||||
The default is ``'{slug}-{lang}.html``.
|
||||
The default is ``"{slug}-{lang}.html"``.
|
||||
|
||||
.. data:: ARTICLE_LANG_SAVE_AS
|
||||
|
||||
The place where we will save an article which doesn't use the default
|
||||
language. The default is ``'{slug}-{lang}.html'``.
|
||||
language. The default is ``"{slug}-{lang}.html"``.
|
||||
|
||||
.. data:: DRAFT_URL
|
||||
|
||||
The URL to refer to an article draft. The default is
|
||||
``'drafts/{slug}.html'``.
|
||||
``"drafts/{slug}.html"``.
|
||||
|
||||
.. data:: DRAFT_SAVE_AS
|
||||
|
||||
The place where we will save an article draft. The default is ``'drafts/{slug}.html'``.
|
||||
The place where we will save an article draft. The default is ``"drafts/{slug}.html"``.
|
||||
|
||||
.. data:: DRAFT_LANG_URL
|
||||
|
||||
The URL to refer to an article draft which doesn't use the default language.
|
||||
The default is ``'drafts/{slug}-{lang}.html'``.
|
||||
The default is ``"drafts/{slug}-{lang}.html"``.
|
||||
|
||||
.. data:: DRAFT_LANG_SAVE_AS
|
||||
|
||||
The place where we will save an article draft which doesn't use the default
|
||||
language. The default is ``'drafts/{slug}-{lang}.html'``.
|
||||
language. The default is ``"drafts/{slug}-{lang}.html"``.
|
||||
|
||||
.. data:: PAGE_URL
|
||||
|
||||
The URL we will use to link to a page. The default is
|
||||
``'pages/{slug}.html'``.
|
||||
``"pages/{slug}.html"``.
|
||||
|
||||
.. data:: PAGE_SAVE_AS
|
||||
|
||||
The location we will save the page. This value has to be the same as
|
||||
PAGE_URL or you need to use a rewrite in your server config. The default
|
||||
is ``'pages/{slug}.html'``.
|
||||
is ``"pages/{slug}.html"``.
|
||||
|
||||
.. data:: PAGE_LANG_URL
|
||||
|
||||
The URL we will use to link to a page which doesn't use the default
|
||||
language. The default is ``'pages/{slug}-{lang}.html'``.
|
||||
language. The default is ``"pages/{slug}-{lang}.html"``.
|
||||
|
||||
.. data:: PAGE_LANG_SAVE_AS
|
||||
|
||||
The location we will save the page which doesn't use the default language.
|
||||
The default is ``'pages/{slug}-{lang}.html'``.
|
||||
The default is ``"pages/{slug}-{lang}.html"``.
|
||||
|
||||
.. data:: DRAFT_PAGE_URL
|
||||
|
||||
The URL used to link to a page draft. The default is
|
||||
``'drafts/pages/{slug}.html'``.
|
||||
``"drafts/pages/{slug}.html"``.
|
||||
|
||||
.. data:: DRAFT_PAGE_SAVE_AS
|
||||
|
||||
The actual location a page draft is saved at. The default is
|
||||
``'drafts/pages/{slug}.html'``.
|
||||
``"drafts/pages/{slug}.html"``.
|
||||
|
||||
.. data:: DRAFT_PAGE_LANG_URL
|
||||
|
||||
The URL used to link to a page draft which doesn't use the default
|
||||
language. The default is ``'drafts/pages/{slug}-{lang}.html'``.
|
||||
language. The default is ``"drafts/pages/{slug}-{lang}.html"``.
|
||||
|
||||
.. data:: DRAFT_PAGE_LANG_SAVE_AS
|
||||
|
||||
The actual location a page draft which doesn't use the default language is
|
||||
saved at. The default is ``'drafts/pages/{slug}-{lang}.html'``.
|
||||
saved at. The default is ``"drafts/pages/{slug}-{lang}.html"``.
|
||||
|
||||
.. data:: AUTHOR_URL
|
||||
|
||||
The URL to use for an author. The default is ``'author/{slug}.html'``.
|
||||
The URL to use for an author. The default is ``"author/{slug}.html"``.
|
||||
|
||||
.. data:: AUTHOR_SAVE_AS
|
||||
|
||||
The location to save an author. The default is ``'author/{slug}.html'``.
|
||||
The location to save an author. The default is ``"author/{slug}.html"``.
|
||||
|
||||
.. data:: CATEGORY_URL
|
||||
|
||||
The URL to use for a category. The default is ``'category/{slug}.html'``.
|
||||
The URL to use for a category. The default is ``"category/{slug}.html"``.
|
||||
|
||||
.. data:: CATEGORY_SAVE_AS
|
||||
|
||||
The location to save a category. The default is ``'category/{slug}.html'``.
|
||||
The location to save a category. The default is ``"category/{slug}.html"``.
|
||||
|
||||
.. data:: TAG_URL
|
||||
|
||||
The URL to use for a tag. The default is ``'tag/{slug}.html'``.
|
||||
The URL to use for a tag. The default is ``"tag/{slug}.html"``.
|
||||
|
||||
.. data:: TAG_SAVE_AS
|
||||
|
||||
The location to save the tag page. The default is ``'tag/{slug}.html'``.
|
||||
The location to save the tag page. The default is ``"tag/{slug}.html"``.
|
||||
|
||||
.. note::
|
||||
|
||||
If you do not want one or more of the default pages to be created (e.g.,
|
||||
you are the only author on your site and thus do not need an Authors page),
|
||||
set the corresponding ``*_SAVE_AS`` setting to ``''`` to prevent the
|
||||
set the corresponding ``*_SAVE_AS`` setting to ``""`` to prevent the
|
||||
relevant page from being generated.
|
||||
|
||||
Pelican can optionally create per-year, per-month, and per-day archives of your
|
||||
|
|
@ -615,10 +615,10 @@ written over time.
|
|||
|
||||
Example usage::
|
||||
|
||||
YEAR_ARCHIVE_SAVE_AS = 'posts/{date:%Y}/index.html'
|
||||
YEAR_ARCHIVE_URL = 'posts/{date:%Y}/'
|
||||
MONTH_ARCHIVE_SAVE_AS = 'posts/{date:%Y}/{date:%b}/index.html'
|
||||
MONTH_ARCHIVE_URL = 'posts/{date:%Y}/{date:%b}/'
|
||||
YEAR_ARCHIVE_SAVE_AS = "posts/{date:%Y}/index.html"
|
||||
YEAR_ARCHIVE_URL = "posts/{date:%Y}/"
|
||||
MONTH_ARCHIVE_SAVE_AS = "posts/{date:%Y}/{date:%b}/index.html"
|
||||
MONTH_ARCHIVE_URL = "posts/{date:%Y}/{date:%b}/"
|
||||
|
||||
With these settings, Pelican will create an archive of all your posts for the
|
||||
year at (for instance) ``posts/2011/index.html`` and an archive of all your
|
||||
|
|
@ -632,31 +632,36 @@ through the URLs ``posts/2011/`` and ``posts/2011/Aug/``, respectively.
|
|||
|
||||
.. data:: YEAR_ARCHIVE_SAVE_AS
|
||||
|
||||
The location to save per-year archives of your posts. The default is ``''``.
|
||||
The location to save per-year archives of your posts. The default is ``""``,
|
||||
i.e. this is disabled by default.
|
||||
|
||||
.. data:: YEAR_ARCHIVE_URL
|
||||
|
||||
The URL to use for per-year archives of your posts. You should set this if
|
||||
you enable per-year archives. The default is ``''``.
|
||||
you enable per-year archives. The default is ``""``, i.e. this is disabled
|
||||
by default.
|
||||
|
||||
.. data:: MONTH_ARCHIVE_SAVE_AS
|
||||
|
||||
The location to save per-month archives of your posts. The default is
|
||||
``''``.
|
||||
``""``, i.e. this is disabled by default.
|
||||
|
||||
.. data:: MONTH_ARCHIVE_URL
|
||||
|
||||
The URL to use for per-month archives of your posts. You should set this if
|
||||
you enable per-month archives. The default is ``''``.
|
||||
you enable per-month archives. The default is ``""``, i.e. this is disabled
|
||||
by default.
|
||||
|
||||
.. data:: DAY_ARCHIVE_SAVE_AS
|
||||
|
||||
The location to save per-day archives of your posts. The default is ``''``.
|
||||
The location to save per-day archives of your posts. The default is ``""``,
|
||||
i.e. this is disabled by default.
|
||||
|
||||
.. data:: DAY_ARCHIVE_URL
|
||||
|
||||
The URL to use for per-day archives of your posts. You should set this if
|
||||
you enable per-day archives. The default is ``''``.
|
||||
you enable per-day archives. The default is ``""``, i.e. this is disabled by
|
||||
default.
|
||||
|
||||
``DIRECT_TEMPLATES`` work a bit differently than noted above. Only the
|
||||
``_SAVE_AS`` settings are available, but it is available for any direct
|
||||
|
|
@ -664,34 +669,34 @@ template.
|
|||
|
||||
.. data:: ARCHIVES_SAVE_AS
|
||||
|
||||
The location to save the article archives page. The default is ``'archives.html'``.
|
||||
The location to save the article archives page. The default is ``"archives.html"``.
|
||||
|
||||
.. data:: AUTHORS_SAVE_AS
|
||||
|
||||
The location to save the author list. The default is ``'authors.html'``.
|
||||
The location to save the author list. The default is ``"authors.html"``.
|
||||
|
||||
.. data:: CATEGORIES_SAVE_AS
|
||||
|
||||
The location to save the category list. The default is ``'categories.html'``.
|
||||
The location to save the category list. The default is ``"categories.html"``.
|
||||
|
||||
.. data:: TAGS_SAVE_AS
|
||||
|
||||
The location to save the tag list. The default is ``'tags.html'``.
|
||||
The location to save the tag list. The default is ``"tags.html"``.
|
||||
|
||||
.. data:: INDEX_SAVE_AS
|
||||
|
||||
The location to save the list of all articles. The default is ``'index.html'``.
|
||||
The location to save the list of all articles. The default is ``"index.html"``.
|
||||
|
||||
URLs for direct template pages are theme-dependent. Some themes use
|
||||
corresponding ``*_URL`` setting as string, while others hard-code them:
|
||||
``'archives.html'``, ``'authors.html'``, ``'categories.html'``,
|
||||
``'tags.html'``.
|
||||
``"archives.html"``, ``"authors.html"``, ``"categories.html"``,
|
||||
``"tags.html"``.
|
||||
|
||||
.. data:: SLUGIFY_SOURCE
|
||||
|
||||
Specifies from where you want the slug to be automatically generated. Can be
|
||||
set to ``title`` to use the "Title:" metadata tag or ``basename`` to use the
|
||||
article's file name when creating the slug. The default is ``'title'``.
|
||||
article's file name when creating the slug. The default is ``"title"``.
|
||||
|
||||
.. data:: SLUGIFY_USE_UNICODE
|
||||
|
||||
|
|
@ -715,10 +720,10 @@ corresponding ``*_URL`` setting as string, while others hard-code them:
|
|||
backward compatibility with existing URLs. The default is::
|
||||
|
||||
[
|
||||
(r'[^\w\s-]', ''), # remove non-alphabetical/whitespace/'-' chars
|
||||
(r'(?u)\A\s*', ''), # strip leading whitespace
|
||||
(r'(?u)\s*\Z', ''), # strip trailing whitespace
|
||||
(r'[-\s]+', '-'), # reduce multiple whitespace or '-' to single '-'
|
||||
(r"[^\w\s-]", ""), # remove non-alphabetical/whitespace/"-" chars
|
||||
(r"(?u)\A\s*", ""), # strip leading whitespace
|
||||
(r"(?u)\s*\Z", ""), # strip trailing whitespace
|
||||
(r"[-\s]+", "-"), # reduce multiple whitespace or "-" to single "-"
|
||||
]
|
||||
|
||||
.. data:: AUTHOR_REGEX_SUBSTITUTIONS
|
||||
|
|
@ -756,7 +761,7 @@ Time and Date
|
|||
|
||||
.. data:: DEFAULT_DATE
|
||||
|
||||
The default date you want to use. If ``'fs'``, Pelican will use the file
|
||||
The default date you want to use. If ``"fs"``, Pelican will use the file
|
||||
system timestamp information (mtime) if it can't get date information from
|
||||
the metadata. If given any other string, it will be parsed by the same
|
||||
method as article metadata. If set to a tuple object, the default datetime
|
||||
|
|
@ -765,7 +770,8 @@ Time and Date
|
|||
|
||||
.. data:: DEFAULT_DATE_FORMAT
|
||||
|
||||
The default date format you want to use. The default is ``'%a %d %B %Y'``.
|
||||
The default date format you want to use. The default is ``"%a %d %B %Y"``,
|
||||
e.g. "Mon 06 April 2026".
|
||||
|
||||
.. data:: DATE_FORMATS
|
||||
|
||||
|
|
@ -785,8 +791,8 @@ Time and Date
|
|||
.. parsed-literal::
|
||||
|
||||
DATE_FORMATS = {
|
||||
'en': '%a, %d %b %Y',
|
||||
'jp': '%Y-%m-%d(%a)',
|
||||
"en": "%a, %d %b %Y",
|
||||
"jp": "%Y-%m-%d(%a)",
|
||||
}
|
||||
|
||||
It is also possible to set different locale settings for each language by
|
||||
|
|
@ -797,14 +803,14 @@ Time and Date
|
|||
|
||||
# On Unix/Linux
|
||||
DATE_FORMATS = {
|
||||
'en': ('en_US','%a, %d %b %Y'),
|
||||
'jp': ('ja_JP','%Y-%m-%d(%a)'),
|
||||
"en": ("en_US", "%a, %d %b %Y"),
|
||||
"jp": ("ja_JP", "%Y-%m-%d(%a)"),
|
||||
}
|
||||
|
||||
# On Windows
|
||||
DATE_FORMATS = {
|
||||
'en': ('usa','%a, %d %b %Y'),
|
||||
'jp': ('jpn','%Y-%m-%d(%a)'),
|
||||
"en": ("usa", "%a, %d %b %Y"),
|
||||
"jp": ("jpn", "%Y-%m-%d(%a)"),
|
||||
}
|
||||
|
||||
The default is ``{}``.
|
||||
|
|
@ -819,8 +825,9 @@ Time and Date
|
|||
|
||||
.. parsed-literal::
|
||||
|
||||
LOCALE = ['usa', 'jpn', # On Windows
|
||||
'en_US', 'ja_JP' # On Unix/Linux
|
||||
LOCALE = [
|
||||
"usa", "jpn", # On Windows
|
||||
"en_US", "ja_JP" # On Unix/Linux
|
||||
]
|
||||
|
||||
For a list of available locales refer to `locales on Windows`_ or on
|
||||
|
|
@ -854,28 +861,30 @@ Template pages
|
|||
For instance, if you have a blog with three static pages — a list of books,
|
||||
your resume, and a contact page — you could have::
|
||||
|
||||
TEMPLATE_PAGES = {'src/books.html': 'dest/books.html',
|
||||
'src/resume.html': 'dest/resume.html',
|
||||
'src/contact.html': 'dest/contact.html'}
|
||||
TEMPLATE_PAGES = {
|
||||
"src/books.html": "dest/books.html",
|
||||
"src/resume.html": "dest/resume.html",
|
||||
"src/contact.html": "dest/contact.html",
|
||||
}
|
||||
|
||||
The default is ``{}``.
|
||||
|
||||
.. data:: TEMPLATE_EXTENSIONS
|
||||
|
||||
The extensions to use when looking up template files from template names.
|
||||
The default is ``['.html']``.
|
||||
The default is ``[".html"]``.
|
||||
|
||||
.. data:: DIRECT_TEMPLATES
|
||||
|
||||
List of templates that are used directly to render content. Typically direct
|
||||
templates are used to generate index pages for collections of content (e.g.,
|
||||
category and tag index pages). If the author, category and tag collections are not
|
||||
needed, set ``DIRECT_TEMPLATES = ['index', 'archives']``
|
||||
needed, set ``DIRECT_TEMPLATES = ["index", "archives"]``
|
||||
|
||||
``DIRECT_TEMPLATES`` are searched for over paths maintained in
|
||||
``THEME_TEMPLATES_OVERRIDES``.
|
||||
|
||||
The default is ``['index', 'tags', 'categories', 'authors', 'archives']``.
|
||||
The default is ``["index", "tags", "categories", "authors", "archives"]``.
|
||||
|
||||
Metadata
|
||||
========
|
||||
|
|
@ -893,18 +902,37 @@ Metadata
|
|||
|
||||
The regexp that will be used to extract any metadata from the filename. All
|
||||
named groups that are matched will be set in the metadata object. The
|
||||
default value will only extract the date from the filename.
|
||||
default value is ``r"(?P<date>\d{4}-\d{2}-\d{2}).*"`` and will only extract
|
||||
the date from the filename.
|
||||
|
||||
For example, to extract both the date and the slug::
|
||||
For example, if your source file were titled ``2026-04-30_blog-article.md``,
|
||||
you could extract both the date and the slug::
|
||||
|
||||
FILENAME_METADATA = r'(?P<date>\d{4}-\d{2}-\d{2})_(?P<slug>.*)'
|
||||
FILENAME_METADATA = r"(?P<date>\d{4}-\d{2}-\d{2})_(?P<slug>.*)"
|
||||
|
||||
See also ``SLUGIFY_SOURCE``. The default is ``r'(?P<date>\d{4}-\d{2}-\d{2}).*'``.
|
||||
giving you a date of *April 30, 2026* and a slug of *blog-article*.
|
||||
|
||||
See also ``SLUGIFY_SOURCE``. The default is
|
||||
``r"(?P<date>\d{4}-\d{2}-\d{2}).*"``, i.e. it assumed your filenames start
|
||||
with an ISO-style date, e.g. ``2026-04-30``.
|
||||
|
||||
See also, ``FILENAME_METADATA``.
|
||||
|
||||
.. data:: PATH_METADATA
|
||||
|
||||
Like ``FILENAME_METADATA``, but parsed from a page's full path relative to
|
||||
the content source directory. The default is ``''``.
|
||||
the content source directory, include the source filename. The default
|
||||
value is ``""``.
|
||||
|
||||
For example, if your source files were stored in folders by year and then my
|
||||
month, with the filename being the day of the month, (e.g.
|
||||
``2026/04/30.rst``) you could extract that with::
|
||||
|
||||
PATH_METADATA = r"(?P<date>\d{4}/\d{2}/\d{2}).*"
|
||||
|
||||
(The above works on Windows as well.)
|
||||
|
||||
See also ``FILENAME_METADATA``.
|
||||
|
||||
.. data:: EXTRA_PATH_METADATA
|
||||
|
||||
|
|
@ -913,44 +941,44 @@ Metadata
|
|||
unlike some other Pelican file settings. Paths to a directory apply to all
|
||||
files under it. The most-specific path wins conflicts.
|
||||
|
||||
Not all metadata needs to be :ref:`embedded in source file itself
|
||||
<internal_metadata>`. For example, blog posts are often named following a
|
||||
``YYYY-MM-DD-SLUG.rst`` pattern, or nested into ``YYYY/MM/DD-SLUG``
|
||||
directories. To extract metadata from the filename or path, set
|
||||
``FILENAME_METADATA`` or ``PATH_METADATA`` to regular expressions that use
|
||||
Python's `group name notation`_ ``(?P<name>…)``. If you want to attach
|
||||
additional metadata but don't want to encode it in the path, you can set
|
||||
``EXTRA_PATH_METADATA``:
|
||||
Not all metadata needs to be :ref:`embedded in source file itself
|
||||
<internal_metadata>`. For example, blog posts are often named following a
|
||||
``YYYY-MM-DD-SLUG.rst`` pattern, or nested into ``YYYY/MM/DD-SLUG``
|
||||
directories. To extract metadata from the filename or path, set
|
||||
``FILENAME_METADATA`` or ``PATH_METADATA`` to regular expressions that use
|
||||
Python's `group name notation`_ ``(?P<name>…)``. If you want to attach
|
||||
additional metadata but don't want to encode it in the path, you can set
|
||||
``EXTRA_PATH_METADATA``:
|
||||
|
||||
.. parsed-literal::
|
||||
.. parsed-literal::
|
||||
|
||||
EXTRA_PATH_METADATA = {
|
||||
'relative/path/to/file-1': {
|
||||
'key-1a': 'value-1a',
|
||||
'key-1b': 'value-1b',
|
||||
},
|
||||
'relative/path/to/file-2': {
|
||||
'key-2': 'value-2',
|
||||
},
|
||||
}
|
||||
EXTRA_PATH_METADATA = {
|
||||
"relative/path/to/file-1": {
|
||||
"key-1a": "value-1a",
|
||||
"key-1b": "value-1b",
|
||||
},
|
||||
"relative/path/to/file-2": {
|
||||
"key-2": "value-2",
|
||||
},
|
||||
}
|
||||
|
||||
This can be a convenient way to shift the installed location of a particular
|
||||
file:
|
||||
This can be a convenient way to shift the output location of a particular
|
||||
file:
|
||||
|
||||
.. parsed-literal::
|
||||
.. parsed-literal::
|
||||
|
||||
# Take advantage of the following defaults
|
||||
# STATIC_SAVE_AS = '{path}'
|
||||
# STATIC_URL = '{path}'
|
||||
STATIC_PATHS = [
|
||||
'static/robots.txt',
|
||||
]
|
||||
EXTRA_PATH_METADATA = {
|
||||
'static/robots.txt': {'path': 'robots.txt'},
|
||||
}
|
||||
# Take advantage of the following defaults:
|
||||
# STATIC_SAVE_AS = "{path}"
|
||||
# STATIC_URL = "{path}"
|
||||
STATIC_PATHS = [
|
||||
"static/robots.txt",
|
||||
]
|
||||
EXTRA_PATH_METADATA = {
|
||||
"static/robots.txt": {"path": "robots.txt"},
|
||||
}
|
||||
|
||||
.. _group name notation:
|
||||
https://docs.python.org/3/library/re.html#regular-expression-syntax
|
||||
.. _group name notation:
|
||||
https://docs.python.org/3/library/re.html#regular-expression-syntax
|
||||
|
||||
The default is ``{}``.
|
||||
|
||||
|
|
@ -993,7 +1021,7 @@ the ``TAG_FEED_ATOM`` and ``TAG_FEED_RSS`` settings:
|
|||
.. data:: FEED_ALL_ATOM
|
||||
|
||||
The location to save the all-posts Atom feed: this feed will contain all
|
||||
posts regardless of their language. The default is ``'feeds/all.atom.xml'``.
|
||||
posts regardless of their language. The default is ``"feeds/all.atom.xml"``.
|
||||
|
||||
.. data:: FEED_ALL_ATOM_URL
|
||||
|
||||
|
|
@ -1014,7 +1042,7 @@ the ``TAG_FEED_ATOM`` and ``TAG_FEED_RSS`` settings:
|
|||
.. data:: CATEGORY_FEED_ATOM
|
||||
|
||||
The location to save the category Atom feeds. [2]_ The default is
|
||||
``'feeds/{slug}.atom.xml'``.
|
||||
``"feeds/{slug}.atom.xml"``.
|
||||
|
||||
.. data:: CATEGORY_FEED_ATOM_URL
|
||||
|
||||
|
|
@ -1036,7 +1064,7 @@ the ``TAG_FEED_ATOM`` and ``TAG_FEED_RSS`` settings:
|
|||
.. data:: AUTHOR_FEED_ATOM
|
||||
|
||||
The location to save the author Atom feeds. [2]_ The default is
|
||||
``'feeds/{slug}.atom.xml'``.
|
||||
``"feeds/{slug}.atom.xml"``.
|
||||
|
||||
.. data:: AUTHOR_FEED_ATOM_URL
|
||||
|
||||
|
|
@ -1047,7 +1075,7 @@ the ``TAG_FEED_ATOM`` and ``TAG_FEED_RSS`` settings:
|
|||
.. data:: AUTHOR_FEED_RSS
|
||||
|
||||
The location to save the author RSS feeds. [2]_ The default is
|
||||
``'feeds/{slug}.rss.xml'``.
|
||||
``"feeds/{slug}.rss.xml"``.
|
||||
|
||||
.. data:: AUTHOR_FEED_RSS_URL
|
||||
|
||||
|
|
@ -1074,7 +1102,7 @@ the ``TAG_FEED_ATOM`` and ``TAG_FEED_RSS`` settings:
|
|||
.. data:: FEED_MAX_ITEMS
|
||||
|
||||
Maximum number of items allowed in a feed. Setting to ``None`` will cause the
|
||||
feed to contains every article. 100 if not specified. The default is ``100``.
|
||||
feed to contains every article. The default is ``100``.
|
||||
|
||||
.. data:: RSS_FEED_SUMMARY_ONLY
|
||||
|
||||
|
|
@ -1118,7 +1146,7 @@ You can use the following settings to configure the pagination.
|
|||
|
||||
The templates to use pagination with, and the number of articles to include
|
||||
on a page. If this value is ``None``, it defaults to ``DEFAULT_PAGINATION``.
|
||||
The default is ``{'index': None, 'tag': None, 'category': None, 'author': None}``.
|
||||
The default is ``{"index": None, "tag": None, "category": None, "author": None}``.
|
||||
|
||||
.. data:: PAGINATION_PATTERNS
|
||||
|
||||
|
|
@ -1126,8 +1154,8 @@ You can use the following settings to configure the pagination.
|
|||
default is::
|
||||
|
||||
(
|
||||
(1, '{name}{extension}', '{name}{extension}'),
|
||||
(2, '{name}{number}{extension}', '{name}{number}{extension}'),
|
||||
(1, "{name}{extension}", "{name}{extension}"),
|
||||
(2, "{name}{number}{extension}", "{name}{number}{extension}""),
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -1152,15 +1180,15 @@ subsequent pages at ``.../page/2/`` etc, you could set ``PAGINATION_PATTERNS``
|
|||
as follows::
|
||||
|
||||
PAGINATION_PATTERNS = (
|
||||
(1, '{url}', '{save_as}'),
|
||||
(2, '{base_name}/page/{number}/', '{base_name}/page/{number}/index.html'),
|
||||
(1, "{url}", "{save_as}"),
|
||||
(2, "{base_name}/page/{number}/", "{base_name}/page/{number}/index.html"),
|
||||
)
|
||||
|
||||
|
||||
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'),
|
||||
(-1, "{base_name}/last/", "{base_name}/last/index.html"),
|
||||
|
||||
Translations
|
||||
============
|
||||
|
|
@ -1170,26 +1198,26 @@ section for more information.
|
|||
|
||||
.. data:: DEFAULT_LANG
|
||||
|
||||
The default language to use. The default is ``'en'``.
|
||||
The default language to use. The default is ``"en"``.
|
||||
|
||||
.. data:: ARTICLE_TRANSLATION_ID
|
||||
|
||||
The metadata attribute(s) used to identify which articles are translations
|
||||
of one another. May be a string or a collection of strings. Set to ``None``
|
||||
or ``False`` to disable the identification of translations. The default is
|
||||
``'slug'``.
|
||||
``"slug"``.
|
||||
|
||||
.. data:: PAGE_TRANSLATION_ID
|
||||
|
||||
The metadata attribute(s) used to identify which pages are translations of
|
||||
one another. May be a string or a collection of strings. Set to ``None`` or
|
||||
``False`` to disable the identification of translations. The default is
|
||||
``'slug'``.
|
||||
``"slug"``.
|
||||
|
||||
.. data:: TRANSLATION_FEED_ATOM
|
||||
|
||||
The location to save the Atom feed for translations. [3]_ The default is
|
||||
``'feeds/all-{lang}.atom.xml'``.
|
||||
``"feeds/all-{lang}.atom.xml"``.
|
||||
|
||||
.. data:: TRANSLATION_FEED_ATOM_URL
|
||||
|
||||
|
|
@ -1227,18 +1255,18 @@ 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
|
||||
to reverse the sort order), special option ``'basename'`` which will use
|
||||
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
|
||||
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). The
|
||||
default is ``'reversed-date'``.
|
||||
default is ``"reversed-date"``.
|
||||
|
||||
.. data:: PAGE_ORDER_BY
|
||||
|
||||
Defines how the pages (``pages`` variable in the template) are sorted.
|
||||
Options are same as ``ARTICLE_ORDER_BY``. The default value, ``'basename'``
|
||||
will sort pages by their basename. The default is ``'basename'``.
|
||||
Options are same as ``ARTICLE_ORDER_BY``. The default value, ``"basename"``
|
||||
will sort pages by their basename. The default is ``"basename"``.
|
||||
|
||||
|
||||
.. _settings/themes:
|
||||
|
|
@ -1260,14 +1288,14 @@ themes.
|
|||
|
||||
Destination directory in the output path where Pelican will place the files
|
||||
collected from `THEME_STATIC_PATHS`. Default is `theme`. The default is
|
||||
``'theme'``.
|
||||
``"theme"``.
|
||||
|
||||
.. data:: THEME_STATIC_PATHS
|
||||
|
||||
Static theme paths you want to copy. Default value is `static`, but if your
|
||||
theme has other static paths, you can put them here. If files or directories
|
||||
with the same names are included in the paths defined in this settings, they
|
||||
will be progressively overwritten. The default is ``['static']``.
|
||||
will be progressively overwritten. The default is ``["static"]``.
|
||||
|
||||
.. data:: THEME_TEMPLATES_OVERRIDES
|
||||
|
||||
|
|
@ -1286,7 +1314,7 @@ themes.
|
|||
|
||||
.. data:: CSS_FILE
|
||||
|
||||
Specify the CSS file you want to load. The default is ``'main.css'``.
|
||||
Specify the CSS file you want to load. The default is ``"main.css"``.
|
||||
|
||||
By default, two themes are available. You can specify them using the ``THEME``
|
||||
setting or by passing the ``-t`` option to the ``pelican`` command:
|
||||
|
|
@ -1313,7 +1341,10 @@ Following are example ways to specify your preferred theme::
|
|||
# Specify a customized theme, via absolute path
|
||||
THEME = "/home/myuser/projects/mysite/themes/mycustomtheme"
|
||||
|
||||
The built-in ``simple`` theme can be customized using the following settings.
|
||||
Simple Theme
|
||||
------------
|
||||
|
||||
The built-in ``simple`` theme can be customized using the following settings:
|
||||
|
||||
.. data:: STYLESHEET_URL
|
||||
|
||||
|
|
@ -1383,6 +1414,9 @@ Feel free to use them in your themes as well.
|
|||
Allows override of the name of the "social" widget. If not specified,
|
||||
defaults to "social". The default is ``None``.
|
||||
|
||||
Notmyidea Theme
|
||||
---------------
|
||||
|
||||
In addition, you can use the "wide" version of the ``notmyidea`` theme by
|
||||
adding the following to your configuration::
|
||||
|
||||
|
|
@ -1405,7 +1439,7 @@ they will be filtered out.
|
|||
For example::
|
||||
|
||||
import logging
|
||||
LOG_FILTER = [(logging.WARN, 'TAG_SAVE_AS is set to False')]
|
||||
LOG_FILTER = [(logging.WARN, "TAG_SAVE_AS is set to False")]
|
||||
|
||||
It is possible to filter out messages by a template. Check out source code to
|
||||
obtain a template.
|
||||
|
|
@ -1413,7 +1447,7 @@ obtain a template.
|
|||
For example::
|
||||
|
||||
import logging
|
||||
LOG_FILTER = [(logging.WARN, 'Empty alt attribute for image %s in %s')]
|
||||
LOG_FILTER = [(logging.WARN, "Empty alt attribute for image %s in %s")]
|
||||
|
||||
.. Warning::
|
||||
|
||||
|
|
@ -1428,7 +1462,7 @@ For example::
|
|||
.. _reading_only_modified_content:
|
||||
|
||||
|
||||
Reading only modified content
|
||||
Reading Only Modified Content
|
||||
=============================
|
||||
|
||||
To speed up the build process, Pelican can optionally read only articles and
|
||||
|
|
@ -1442,12 +1476,12 @@ When Pelican is about to read some content source file:
|
|||
file has no record in the cache file, it is read as usual.
|
||||
2. The file is checked according to ``CHECK_MODIFIED_METHOD``:
|
||||
|
||||
- If set to ``'mtime'``, the modification time of the file is
|
||||
checked.
|
||||
- If set to a name of a function provided by the ``hashlib``
|
||||
module, e.g. ``'md5'``, the file hash is checked.
|
||||
- If set to anything else or the necessary information about the
|
||||
file cannot be found in the cache file, the content is read as usual.
|
||||
- If set to ``"mtime"``, the modification time of the file is
|
||||
checked.
|
||||
- If set to a name of a function provided by the ``hashlib``
|
||||
module, e.g. ``"md5"``, the file hash is checked.
|
||||
- If set to anything else or the necessary information about the
|
||||
file cannot be found in the cache file, the content is read as usual.
|
||||
|
||||
3. If the file is considered unchanged, the content data saved in a
|
||||
previous build corresponding to the file is loaded from the cache, and the
|
||||
|
|
@ -1456,9 +1490,9 @@ When Pelican is about to read some content source file:
|
|||
modification information and the content data are saved to the cache if
|
||||
``CACHE_CONTENT`` is ``True``.
|
||||
|
||||
If ``CONTENT_CACHING_LAYER`` is set to ``'reader'`` (the default), the raw
|
||||
If ``CONTENT_CACHING_LAYER`` is set to ``"reader"`` (the default), the raw
|
||||
content and metadata returned by a reader are cached. If this setting is
|
||||
instead set to ``'generator'``, the processed content object is cached. Caching
|
||||
instead set to ``"generator"``, the processed content object is cached. Caching
|
||||
the processed content object may conflict with plugins (as some reading related
|
||||
signals may be skipped) and the ``WITH_FUTURE_DATES`` functionality (as the
|
||||
``draft`` status of the cached content objects would not change automatically
|
||||
|
|
|
|||
|
|
@ -10,6 +10,12 @@ Please note that while we do our best to review and merge theme contributions,
|
|||
they are submitted by the Pelican community and thus may have varying levels of
|
||||
support and interoperability.
|
||||
|
||||
Community themes can also be found on PyPI tagged with "`Framework ::
|
||||
Pelican :: Themes`_".
|
||||
|
||||
.. _Framework :: Pelican :: Themes: https://pypi.org/search/?q=&o=-created&c=Framework+%3A%3A+Pelican+%3A%3A+Themes
|
||||
|
||||
|
||||
Creating Themes
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
104
docs/tips.rst
104
docs/tips.rst
|
|
@ -205,53 +205,63 @@ the workflow, for example:
|
|||
|
||||
Here's the complete list of workflow inputs:
|
||||
|
||||
+------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| Name | Required | Description | Type | Default |
|
||||
+==================+==========+============================================+========+===============+
|
||||
| ``settings`` | Yes | The path to your Pelican settings | string | |
|
||||
| | | file (``pelican``'s | | |
|
||||
| | | ``--settings`` option), | | |
|
||||
| | | for example: ``"publishconf.py"`` | | |
|
||||
+------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``requirements`` | No | The Python requirements to | string | ``"pelican"`` |
|
||||
| | | install, for example to enable | | |
|
||||
| | | markdown and typogrify use: | | |
|
||||
| | | ``"pelican[markdown] typogrify"`` | | |
|
||||
| | | or if you have a requirements | | |
|
||||
| | | file: ``"-r requirements.txt"`` | | |
|
||||
+------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``output-path`` | No | Where to output the generated | string | ``"output/"`` |
|
||||
| | | files (``pelican``'s ``--output`` | | |
|
||||
| | | option) | | |
|
||||
+------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``theme`` | No | The GitHub repo URL of a custom | string | ``""`` |
|
||||
| | | theme to use, for example: | | |
|
||||
| | | ``"https://github.com/seanh/sidecar.git"`` | | |
|
||||
+------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``python`` | No | The version of Python to use to build the | string | ``"3.12"`` |
|
||||
| | | site, for example: ``"3.12"`` (to use the | | |
|
||||
| | | most recent version of Python 3.12, this | | |
|
||||
| | | is faster) or ``"3.12.1"`` (to use an | | |
|
||||
| | | exact version, slower) | | |
|
||||
+------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``siteurl`` | No | The base URL of your web site (Pelican's | string | The URL of |
|
||||
| | | ``SITEURL`` setting). If not passed this | | your GitHub |
|
||||
| | | will default to the URL of your GitHub | | Pages site. |
|
||||
| | | Pages site, which is correct in most | | |
|
||||
| | | cases. | | |
|
||||
+------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``feed_domain`` | No | The domain to be prepended to feed URLs | string | The URL of |
|
||||
| | | (Pelican's ``FEED_DOMAIN`` setting). If | | your GitHub |
|
||||
| | | not passed this will default to the URL of | | Pages site. |
|
||||
| | | your GitHub Pages site, which is correct | | |
|
||||
| | | in most cases. | | |
|
||||
+------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``deploy`` | No | This is used to determine whether you will | bool | ``true`` |
|
||||
| | | deploy the site or not to GitHub Pages. | | |
|
||||
| | | This is most useful if you want to test a | | |
|
||||
| | | change to your website in a pull request | | |
|
||||
| | | before deploying those change. | | |
|
||||
+------------------+----------+--------------------------------------------+--------+---------------+
|
||||
+--------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| Name | Required | Description | Type | Default |
|
||||
+====================+==========+============================================+========+===============+
|
||||
| ``settings`` | Yes | The path to your Pelican settings | string | |
|
||||
| | | file (``pelican``'s | | |
|
||||
| | | ``--settings`` option), | | |
|
||||
| | | for example: ``"publishconf.py"`` | | |
|
||||
+--------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``requirements`` | No | The Python requirements to | string | ``"pelican"`` |
|
||||
| | | install, for example to enable | | |
|
||||
| | | markdown and typogrify use: | | |
|
||||
| | | ``"pelican[markdown] typogrify"`` | | |
|
||||
| | | or if you have a requirements | | |
|
||||
| | | file: ``"-r requirements.txt"`` | | |
|
||||
+--------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``output-path`` | No | Where to output the generated | string | ``"output/"`` |
|
||||
| | | files (``pelican``'s ``--output`` | | |
|
||||
| | | option) | | |
|
||||
+--------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``theme`` | No | The GitHub repo URL of a custom | string | ``""`` |
|
||||
| | | theme to use, for example: | | |
|
||||
| | | ``"https://github.com/seanh/sidecar.git"`` | | |
|
||||
+--------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``theme-checkout`` | No | Git ref (branch, tag or commit) of the | string | ``""`` |
|
||||
| | | theme repo to checkout. This can be used | | |
|
||||
| | | to pin the version of your theme. If not | | |
|
||||
| | | specified defaults to the theme repo's | | |
|
||||
| | | default branch. | | |
|
||||
+--------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``python`` | No | The version of Python to use to build the | string | ``"3.12"`` |
|
||||
| | | site, for example: ``"3.12"`` (to use the | | |
|
||||
| | | most recent version of Python 3.12, this | | |
|
||||
| | | is faster) or ``"3.12.1"`` (to use an | | |
|
||||
| | | exact version, slower) | | |
|
||||
+--------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``siteurl`` | No | The base URL of your web site (Pelican's | string | The URL of |
|
||||
| | | ``SITEURL`` setting). If not passed this | | your GitHub |
|
||||
| | | will default to the URL of your GitHub | | Pages site. |
|
||||
| | | Pages site, which is correct in most | | |
|
||||
| | | cases. | | |
|
||||
+--------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``feed_domain`` | No | The domain to be prepended to feed URLs | string | The URL of |
|
||||
| | | (Pelican's ``FEED_DOMAIN`` setting). If | | your GitHub |
|
||||
| | | not passed this will default to the URL of | | Pages site. |
|
||||
| | | your GitHub Pages site, which is correct | | |
|
||||
| | | in most cases. | | |
|
||||
+--------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``deploy`` | No | This is used to determine whether you will | bool | ``true`` |
|
||||
| | | deploy the site or not to GitHub Pages. | | |
|
||||
| | | This is most useful if you want to test a | | |
|
||||
| | | change to your website in a pull request | | |
|
||||
| | | before deploying those change. | | |
|
||||
+--------------------+----------+--------------------------------------------+--------+---------------+
|
||||
| ``stork`` | No | This is used to determine whether Stork | bool | ``false`` |
|
||||
| | | will be installed on the runner to be able | | |
|
||||
| | | to build a site with Stork search enabled | | |
|
||||
+--------------------+----------+--------------------------------------------+--------+---------------+
|
||||
|
||||
Testing Your Build in a GitHub Pull Request
|
||||
"""""""""""""""""""""""""""""""""""""""""""
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ from pelican.writers import Writer
|
|||
|
||||
try:
|
||||
__version__ = importlib.metadata.version("pelican")
|
||||
except Exception:
|
||||
except importlib.metadata.PackageNotFoundError:
|
||||
__version__ = "unknown"
|
||||
|
||||
DEFAULT_CONFIG_NAME = "pelicanconf.py"
|
||||
|
|
@ -78,11 +78,10 @@ class Pelican:
|
|||
try:
|
||||
plugin.register()
|
||||
self.plugins.append(plugin)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Cannot register plugin `%s`\n%s",
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Cannot register plugin `%s`",
|
||||
name,
|
||||
e,
|
||||
stacklevel=2,
|
||||
)
|
||||
if self.settings.get("DEBUG", False):
|
||||
|
|
@ -258,7 +257,7 @@ class PrintSettings(argparse.Action):
|
|||
try:
|
||||
instance, settings = get_instance(namespace)
|
||||
except Exception as e:
|
||||
logger.critical("%s: %s", e.__class__.__name__, e)
|
||||
logger.critical("%s", e.__class__.__name__, exc_info=True)
|
||||
console.print_exception()
|
||||
sys.exit(getattr(e, "exitcode", 1))
|
||||
|
||||
|
|
@ -267,7 +266,7 @@ class PrintSettings(argparse.Action):
|
|||
for setting in values:
|
||||
if setting in settings:
|
||||
# Only add newline between setting name and value if dict
|
||||
if isinstance(settings[setting], (dict, tuple, list)):
|
||||
if isinstance(settings[setting], dict | tuple | list):
|
||||
setting_format = "\n{}:\n{}"
|
||||
else:
|
||||
setting_format = "\n{}: {}"
|
||||
|
|
@ -621,7 +620,8 @@ def listen(server, port, output, excqueue=None):
|
|||
except Exception as e:
|
||||
if excqueue is not None:
|
||||
excqueue.put(traceback.format_exception_only(type(e), e)[-1])
|
||||
return
|
||||
else:
|
||||
logging.exception("Listening aborted unexpectedly.")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
httpd.socket.close()
|
||||
|
|
@ -680,7 +680,7 @@ def main(argv=None):
|
|||
except KeyboardInterrupt:
|
||||
logger.warning("Keyboard interrupt received. Exiting.")
|
||||
except Exception as e:
|
||||
logger.critical("%s: %s", e.__class__.__name__, e)
|
||||
logger.critical("%s: %s", e.__class__.__name__, e, exc_info=True)
|
||||
|
||||
if args.verbosity == logging.DEBUG:
|
||||
console.print_exception()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import logging
|
|||
import os
|
||||
import re
|
||||
from html import unescape
|
||||
from typing import Any, Optional
|
||||
from typing import Any
|
||||
from urllib.parse import ParseResult, unquote, urljoin, urlparse, urlunparse
|
||||
|
||||
try:
|
||||
|
|
@ -46,7 +46,7 @@ class Content:
|
|||
|
||||
"""
|
||||
|
||||
default_template: Optional[str] = None
|
||||
default_template: str | None = None
|
||||
mandatory_properties: tuple[str, ...] = ()
|
||||
|
||||
@deprecated_attribute(old="filename", new="source_path", since=(3, 2, 0))
|
||||
|
|
@ -56,10 +56,10 @@ class Content:
|
|||
def __init__(
|
||||
self,
|
||||
content: str,
|
||||
metadata: Optional[dict[str, Any]] = None,
|
||||
settings: Optional[Settings] = None,
|
||||
source_path: Optional[str] = None,
|
||||
context: Optional[dict[Any, Any]] = None,
|
||||
metadata: dict[str, Any] | None = None,
|
||||
settings: Settings | None = None,
|
||||
source_path: str | None = None,
|
||||
context: dict[Any, Any] | None = None,
|
||||
):
|
||||
if metadata is None:
|
||||
metadata = {}
|
||||
|
|
@ -242,7 +242,7 @@ class Content:
|
|||
)
|
||||
return metadata
|
||||
|
||||
def _expand_settings(self, key: str, klass: Optional[str] = None) -> str:
|
||||
def _expand_settings(self, key: str, klass: str | None = None) -> str:
|
||||
if not klass:
|
||||
klass = self.__class__.__name__
|
||||
fq_key = (f"{klass}_{key}").upper()
|
||||
|
|
@ -282,10 +282,10 @@ class Content:
|
|||
# XXX Put this in a different location.
|
||||
if what in {"filename", "static", "attach"}:
|
||||
|
||||
def _get_linked_content(key: str, url: ParseResult) -> Optional[Content]:
|
||||
def _get_linked_content(key: str, url: ParseResult) -> Content | None:
|
||||
nonlocal value
|
||||
|
||||
def _find_path(path: str) -> Optional[Content]:
|
||||
def _find_path(path: str) -> Content | None:
|
||||
if path.startswith("/"):
|
||||
path = path[1:]
|
||||
else:
|
||||
|
|
@ -501,9 +501,7 @@ class Content:
|
|||
else:
|
||||
return self.default_template
|
||||
|
||||
def get_relative_source_path(
|
||||
self, source_path: Optional[str] = None
|
||||
) -> Optional[str]:
|
||||
def get_relative_source_path(self, source_path: str | None = None) -> str | None:
|
||||
"""Return the relative path (from the content path) to the given
|
||||
source_path.
|
||||
|
||||
|
|
@ -599,7 +597,7 @@ class Article(Content):
|
|||
if self.date.tzinfo is None:
|
||||
now = datetime.datetime.now()
|
||||
else:
|
||||
now = datetime.datetime.now(datetime.timezone.utc)
|
||||
now = datetime.datetime.now(datetime.UTC)
|
||||
if self.date > now:
|
||||
self.status = "draft"
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ from collections import defaultdict
|
|||
from functools import partial
|
||||
from itertools import chain, groupby
|
||||
from operator import attrgetter
|
||||
from typing import Optional
|
||||
|
||||
from jinja2 import (
|
||||
BaseLoader,
|
||||
|
|
@ -31,6 +30,7 @@ from pelican.utils import (
|
|||
posixize_path,
|
||||
process_translations,
|
||||
)
|
||||
from pelican.writers import FileOverwriteFailedError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -158,7 +158,7 @@ class Generator:
|
|||
return False
|
||||
|
||||
def get_files(
|
||||
self, paths, exclude: Optional[list[str]] = None, extensions=None
|
||||
self, paths, exclude: list[str] | None = None, extensions=None
|
||||
) -> set[str]:
|
||||
"""Return a list of files to use, based on rules
|
||||
|
||||
|
|
@ -253,7 +253,7 @@ class Generator:
|
|||
# return the name of the class for logging purposes
|
||||
return self.__class__.__name__
|
||||
|
||||
def _check_disabled_readers(self, paths, exclude: Optional[list[str]]) -> None:
|
||||
def _check_disabled_readers(self, paths, exclude: list[str] | None) -> None:
|
||||
"""Log warnings for files that would have been processed by disabled readers."""
|
||||
for fil in self.get_files(
|
||||
paths, exclude=exclude, extensions=self.readers.disabled_extensions
|
||||
|
|
@ -571,57 +571,93 @@ class ArticlesGenerator(CachingGenerator):
|
|||
tag_template = self.get_template("tag")
|
||||
for tag, articles in self.tags.items():
|
||||
dates = [article for article in self.dates if article in articles]
|
||||
write(
|
||||
tag.save_as,
|
||||
tag_template,
|
||||
self.context,
|
||||
tag=tag,
|
||||
url=tag.url,
|
||||
articles=articles,
|
||||
dates=dates,
|
||||
template_name="tag",
|
||||
blog=True,
|
||||
page_name=tag.page_name,
|
||||
all_articles=self.articles,
|
||||
)
|
||||
try:
|
||||
write(
|
||||
tag.save_as,
|
||||
tag_template,
|
||||
self.context,
|
||||
tag=tag,
|
||||
url=tag.url,
|
||||
articles=articles,
|
||||
dates=dates,
|
||||
template_name="tag",
|
||||
blog=True,
|
||||
page_name=tag.page_name,
|
||||
all_articles=self.articles,
|
||||
)
|
||||
except FileOverwriteFailedError:
|
||||
if not tag.slug:
|
||||
logger.info(
|
||||
'Tag "%s" has an invalid slug; skipping writing tag page...',
|
||||
tag,
|
||||
extra={"limit_msg": "Further tags with invalid slugs."},
|
||||
)
|
||||
continue
|
||||
else:
|
||||
logger.error('Failed to write Tag page for "%s".', tag)
|
||||
raise
|
||||
|
||||
def generate_categories(self, write):
|
||||
"""Generate category pages."""
|
||||
category_template = self.get_template("category")
|
||||
for cat, articles in self.categories:
|
||||
dates = [article for article in self.dates if article in articles]
|
||||
write(
|
||||
cat.save_as,
|
||||
category_template,
|
||||
self.context,
|
||||
url=cat.url,
|
||||
category=cat,
|
||||
articles=articles,
|
||||
dates=dates,
|
||||
template_name="category",
|
||||
blog=True,
|
||||
page_name=cat.page_name,
|
||||
all_articles=self.articles,
|
||||
)
|
||||
try:
|
||||
write(
|
||||
cat.save_as,
|
||||
category_template,
|
||||
self.context,
|
||||
url=cat.url,
|
||||
category=cat,
|
||||
articles=articles,
|
||||
dates=dates,
|
||||
template_name="category",
|
||||
blog=True,
|
||||
page_name=cat.page_name,
|
||||
all_articles=self.articles,
|
||||
)
|
||||
except FileOverwriteFailedError:
|
||||
if not cat.slug:
|
||||
logger.info(
|
||||
'Category "%s" has an invalid slug; skipping writing category page...',
|
||||
cat,
|
||||
extra={"limit_msg": "Further categories with invalid slugs."},
|
||||
)
|
||||
continue
|
||||
else:
|
||||
logger.error('Failed to write Category page for "%s".', cat)
|
||||
raise
|
||||
|
||||
def generate_authors(self, write):
|
||||
"""Generate Author pages."""
|
||||
author_template = self.get_template("author")
|
||||
for aut, articles in self.authors:
|
||||
dates = [article for article in self.dates if article in articles]
|
||||
write(
|
||||
aut.save_as,
|
||||
author_template,
|
||||
self.context,
|
||||
url=aut.url,
|
||||
author=aut,
|
||||
articles=articles,
|
||||
dates=dates,
|
||||
template_name="author",
|
||||
blog=True,
|
||||
page_name=aut.page_name,
|
||||
all_articles=self.articles,
|
||||
)
|
||||
try:
|
||||
write(
|
||||
aut.save_as,
|
||||
author_template,
|
||||
self.context,
|
||||
url=aut.url,
|
||||
author=aut,
|
||||
articles=articles,
|
||||
dates=dates,
|
||||
template_name="author",
|
||||
blog=True,
|
||||
page_name=aut.page_name,
|
||||
all_articles=self.articles,
|
||||
)
|
||||
except FileOverwriteFailedError:
|
||||
if not aut.slug:
|
||||
logger.info(
|
||||
'Author "%s" has an invalid slug; skipping writing author page...',
|
||||
aut,
|
||||
extra={"limit_msg": "Further authors with invalid slugs."},
|
||||
)
|
||||
continue
|
||||
else:
|
||||
logger.error('Failed to write Author page for "%s".', aut)
|
||||
raise
|
||||
|
||||
def generate_drafts(self, write):
|
||||
"""Generate drafts pages."""
|
||||
|
|
@ -681,11 +717,10 @@ class ArticlesGenerator(CachingGenerator):
|
|||
context_signal=signals.article_generator_context,
|
||||
context_sender=self,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Could not process %s\n%s",
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Could not process %s",
|
||||
f,
|
||||
e,
|
||||
exc_info=self.settings.get("DEBUG", False),
|
||||
)
|
||||
self._add_failed_source_path(f)
|
||||
|
|
@ -896,11 +931,10 @@ class PagesGenerator(CachingGenerator):
|
|||
context_signal=signals.page_generator_context,
|
||||
context_sender=self,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Could not process %s\n%s",
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Could not process %s",
|
||||
f,
|
||||
e,
|
||||
exc_info=self.settings.get("DEBUG", False),
|
||||
)
|
||||
self._add_failed_source_path(f)
|
||||
|
|
|
|||
|
|
@ -268,9 +268,11 @@ class RstReader(BaseReader):
|
|||
extra_params.update(user_params)
|
||||
|
||||
pub = docutils.core.Publisher(
|
||||
writer=self.writer_class(), destination_class=docutils.io.StringOutput
|
||||
reader="standalone",
|
||||
parser="restructuredtext",
|
||||
writer=self.writer_class(),
|
||||
destination_class=docutils.io.StringOutput,
|
||||
)
|
||||
pub.set_components("standalone", "restructuredtext", "html")
|
||||
pub.process_programmatic_settings(None, extra_params, None)
|
||||
pub.set_source(source_path=source_path)
|
||||
pub.publish()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import sys
|
|||
from os.path import isabs
|
||||
from pathlib import Path
|
||||
from types import ModuleType
|
||||
from typing import Any, Optional
|
||||
from typing import Any
|
||||
|
||||
from pelican.log import LimitFilter
|
||||
from pelican.paginator import PaginationRule
|
||||
|
|
@ -185,7 +185,7 @@ PYGMENTS_RST_OPTIONS = None
|
|||
|
||||
|
||||
def read_settings(
|
||||
path: Optional[str] = None, override: Optional[Settings] = None
|
||||
path: str | None = None, override: Settings | None = None
|
||||
) -> Settings:
|
||||
settings = override or {}
|
||||
|
||||
|
|
@ -230,7 +230,7 @@ def read_settings(
|
|||
return settings
|
||||
|
||||
|
||||
def get_settings_from_module(module: Optional[ModuleType] = None) -> Settings:
|
||||
def get_settings_from_module(module: ModuleType | None = None) -> Settings:
|
||||
"""Loads settings from a module, returns a dictionary."""
|
||||
|
||||
context = {}
|
||||
|
|
@ -673,9 +673,10 @@ def configure_settings(settings: Settings) -> Settings:
|
|||
]
|
||||
|
||||
if any(settings.get(k) for k in feed_keys):
|
||||
if not settings.get("SITEURL"):
|
||||
if not (settings.get("SITEURL") or settings.get("FEED_DOMAIN")):
|
||||
logger.warning(
|
||||
"Feeds generated without SITEURL set properly may not be valid"
|
||||
"Feeds generated without SITEURL or FEED_DOMAIN set properly"
|
||||
" may not be valid"
|
||||
)
|
||||
|
||||
if "TIMEZONE" not in settings:
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import copy
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
from os.path import abspath, dirname, join
|
||||
|
||||
from pelican import log
|
||||
from pelican.settings import (
|
||||
DEFAULT_CONFIG,
|
||||
DEFAULT_THEME,
|
||||
|
|
@ -11,7 +13,7 @@ from pelican.settings import (
|
|||
handle_deprecated_settings,
|
||||
read_settings,
|
||||
)
|
||||
from pelican.tests.support import unittest
|
||||
from pelican.tests.support import LogCountHandler, unittest
|
||||
|
||||
|
||||
class TestSettingsConfiguration(unittest.TestCase):
|
||||
|
|
@ -108,6 +110,39 @@ class TestSettingsConfiguration(unittest.TestCase):
|
|||
configure_settings(settings)
|
||||
self.assertEqual(settings["FEED_DOMAIN"], "http://feeds.example.com")
|
||||
|
||||
def _feeds_warning_settings(self, **overrides):
|
||||
base = {
|
||||
"LOCALE": "",
|
||||
"PATH": os.curdir,
|
||||
"THEME": DEFAULT_THEME,
|
||||
"FEED_RSS": "feeds/all.rss.xml",
|
||||
}
|
||||
base.update(overrides)
|
||||
handler = LogCountHandler()
|
||||
logger = logging.getLogger()
|
||||
logger.addHandler(handler)
|
||||
saved = log.LimitFilter._raised_messages.copy()
|
||||
log.LimitFilter._raised_messages = set()
|
||||
try:
|
||||
configure_settings(base)
|
||||
return handler.count_logs(
|
||||
"Feeds generated without SITEURL", logging.WARNING
|
||||
)
|
||||
finally:
|
||||
log.LimitFilter._raised_messages = saved
|
||||
logger.removeHandler(handler)
|
||||
|
||||
def test_feeds_warning_with_siteurl(self):
|
||||
self.assertEqual(self._feeds_warning_settings(SITEURL="http://example.com"), 0)
|
||||
|
||||
def test_feeds_warning_with_feed_domain(self):
|
||||
self.assertEqual(
|
||||
self._feeds_warning_settings(FEED_DOMAIN="http://feeds.example.com"), 0
|
||||
)
|
||||
|
||||
def test_feeds_warning_without_siteurl_or_feed_domain(self):
|
||||
self.assertEqual(self._feeds_warning_settings(), 1)
|
||||
|
||||
def test_theme_settings_exceptions(self):
|
||||
settings = self.settings
|
||||
|
||||
|
|
|
|||
|
|
@ -133,6 +133,36 @@ class TestTemplateInheritance(LoggedTestCase):
|
|||
self.assertNotIn("Proudly powered by", content)
|
||||
self.assertIn("New footer", content)
|
||||
|
||||
def test_category_and_tag_feed_titles_use_slug(self):
|
||||
"""Feed link titles on category/tag pages should have unique titles."""
|
||||
|
||||
settings = read_settings(
|
||||
path=None,
|
||||
override={
|
||||
"THEME": "simple",
|
||||
"PATH": CONTENT_DIR,
|
||||
"OUTPUT_PATH": self.temp_output,
|
||||
"CACHE_PATH": self.temp_cache,
|
||||
"SITEURL": "http://example.com",
|
||||
"SITENAME": "My Site",
|
||||
"CATEGORY_FEED_ATOM": "feeds/{slug}.atom.xml",
|
||||
"TAG_FEED_ATOM": "feeds/tag-{slug}.atom.xml",
|
||||
},
|
||||
)
|
||||
|
||||
pelican = Pelican(settings=settings)
|
||||
mute(True)(pelican.run)()
|
||||
|
||||
cat_file = os.path.join(self.temp_output, "category", "test.html")
|
||||
with open(cat_file) as f:
|
||||
cat_content = f.read()
|
||||
self.assertIn('title="Test Category Atom Feed"', cat_content)
|
||||
|
||||
tag_file = os.path.join(self.temp_output, "tag", "foo.html")
|
||||
with open(tag_file) as f:
|
||||
tag_content = f.read()
|
||||
self.assertIn('title="Foo Tag Atom Feed"', tag_content)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import locale
|
|||
import logging
|
||||
import os
|
||||
import shutil
|
||||
from datetime import timezone
|
||||
from datetime import UTC
|
||||
from sys import platform
|
||||
from tempfile import mkdtemp
|
||||
|
||||
|
|
@ -62,10 +62,15 @@ class TestUtils(LoggedTestCase):
|
|||
date = utils.SafeDatetime(year=2012, month=11, day=22)
|
||||
date_hour = utils.SafeDatetime(year=2012, month=11, day=22, hour=22, minute=11)
|
||||
date_hour_z = utils.SafeDatetime(
|
||||
year=2012, month=11, day=22, hour=22, minute=11, tzinfo=timezone.utc
|
||||
year=2012, month=11, day=22, hour=22, minute=11, tzinfo=UTC
|
||||
)
|
||||
date_hour_est = utils.SafeDatetime(
|
||||
year=2012, month=11, day=22, hour=22, minute=11, tzinfo=ZoneInfo("EST")
|
||||
date_hour_wib = utils.SafeDatetime(
|
||||
year=2012,
|
||||
month=11,
|
||||
day=22,
|
||||
hour=22,
|
||||
minute=11,
|
||||
tzinfo=ZoneInfo("Asia/Jakarta"),
|
||||
)
|
||||
date_hour_sec = utils.SafeDatetime(
|
||||
year=2012, month=11, day=22, hour=22, minute=11, second=10
|
||||
|
|
@ -77,16 +82,16 @@ class TestUtils(LoggedTestCase):
|
|||
hour=22,
|
||||
minute=11,
|
||||
second=10,
|
||||
tzinfo=timezone.utc,
|
||||
tzinfo=UTC,
|
||||
)
|
||||
date_hour_sec_est = utils.SafeDatetime(
|
||||
date_hour_sec_wib = utils.SafeDatetime(
|
||||
year=2012,
|
||||
month=11,
|
||||
day=22,
|
||||
hour=22,
|
||||
minute=11,
|
||||
second=10,
|
||||
tzinfo=ZoneInfo("EST"),
|
||||
tzinfo=ZoneInfo("Asia/Jakarta"),
|
||||
)
|
||||
date_hour_sec_frac_z = utils.SafeDatetime(
|
||||
year=2012,
|
||||
|
|
@ -96,7 +101,7 @@ class TestUtils(LoggedTestCase):
|
|||
minute=11,
|
||||
second=10,
|
||||
microsecond=123000,
|
||||
tzinfo=timezone.utc,
|
||||
tzinfo=UTC,
|
||||
)
|
||||
dates = {
|
||||
"2012-11-22": date,
|
||||
|
|
@ -108,10 +113,10 @@ class TestUtils(LoggedTestCase):
|
|||
"22.11.2012": date,
|
||||
"22.11.2012 22:11": date_hour,
|
||||
"2012-11-22T22:11Z": date_hour_z,
|
||||
"2012-11-22T22:11-0500": date_hour_est,
|
||||
"2012-11-22T22:11+0700": date_hour_wib,
|
||||
"2012-11-22 22:11:10": date_hour_sec,
|
||||
"2012-11-22T22:11:10Z": date_hour_sec_z,
|
||||
"2012-11-22T22:11:10-0500": date_hour_sec_est,
|
||||
"2012-11-22T22:11:10+0700": date_hour_sec_wib,
|
||||
"2012-11-22T22:11:10.123Z": date_hour_sec_frac_z,
|
||||
}
|
||||
|
||||
|
|
|
|||
8
pelican/themes/simple/templates/base.html
vendored
8
pelican/themes/simple/templates/base.html
vendored
|
|
@ -25,16 +25,16 @@
|
|||
<link href="{{ FEED_DOMAIN }}/{% if FEED_RSS_URL %}{{ FEED_RSS_URL }}{% else %}{{ FEED_RSS }}{% endif %}" type="application/rss+xml" rel="alternate" title="{{ SITENAME|striptags }} RSS Feed" />
|
||||
{% endif %}
|
||||
{% if CATEGORY_FEED_ATOM and category %}
|
||||
<link href="{{ FEED_DOMAIN }}/{% if CATEGORY_FEED_ATOM_URL %}{{ CATEGORY_FEED_ATOM_URL.format(slug=category.slug) }}{% else %}{{ CATEGORY_FEED_ATOM.format(slug=category.slug) }}{% endif %}" type="application/atom+xml" rel="alternate" title="{{ SITENAME|striptags }} Categories Atom Feed" />
|
||||
<link href="{{ FEED_DOMAIN }}/{% if CATEGORY_FEED_ATOM_URL %}{{ CATEGORY_FEED_ATOM_URL.format(slug=category.slug) }}{% else %}{{ CATEGORY_FEED_ATOM.format(slug=category.slug) }}{% endif %}" type="application/atom+xml" rel="alternate" title="{{ category.slug.title() }} Category Atom Feed" />
|
||||
{% endif %}
|
||||
{% if CATEGORY_FEED_RSS and category %}
|
||||
<link href="{{ FEED_DOMAIN }}/{% if CATEGORY_FEED_RSS_URL %}{{ CATEGORY_FEED_RSS_URL.format(slug=category.slug) }}{% else %}{{ CATEGORY_FEED_RSS.format(slug=category.slug) }}{% endif %}" type="application/rss+xml" rel="alternate" title="{{ SITENAME|striptags }} Categories RSS Feed" />
|
||||
<link href="{{ FEED_DOMAIN }}/{% if CATEGORY_FEED_RSS_URL %}{{ CATEGORY_FEED_RSS_URL.format(slug=category.slug) }}{% else %}{{ CATEGORY_FEED_RSS.format(slug=category.slug) }}{% endif %}" type="application/rss+xml" rel="alternate" title="{{ category.slug.title() }} Category RSS Feed" />
|
||||
{% endif %}
|
||||
{% if TAG_FEED_ATOM and tag %}
|
||||
<link href="{{ FEED_DOMAIN }}/{% if TAG_FEED_ATOM_URL %}{{ TAG_FEED_ATOM_URL.format(slug=tag.slug) }}{% else %}{{ TAG_FEED_ATOM.format(slug=tag.slug) }}{% endif %}" type="application/atom+xml" rel="alternate" title="{{ SITENAME|striptags }} Tags Atom Feed" />
|
||||
<link href="{{ FEED_DOMAIN }}/{% if TAG_FEED_ATOM_URL %}{{ TAG_FEED_ATOM_URL.format(slug=tag.slug) }}{% else %}{{ TAG_FEED_ATOM.format(slug=tag.slug) }}{% endif %}" type="application/atom+xml" rel="alternate" title="{{ tag.slug.title() }} Tag Atom Feed" />
|
||||
{% endif %}
|
||||
{% if TAG_FEED_RSS and tag %}
|
||||
<link href="{{ FEED_DOMAIN }}/{% if TAG_FEED_RSS_URL %}{{ TAG_FEED_RSS_URL.format(slug=tag.slug) }}{% else %}{{ TAG_FEED_RSS.format(slug=tag.slug) }}{% endif %}" type="application/rss+xml" rel="alternate" title="{{ SITENAME|striptags }} Tags RSS Feed" />
|
||||
<link href="{{ FEED_DOMAIN }}/{% if TAG_FEED_RSS_URL %}{{ TAG_FEED_RSS_URL.format(slug=tag.slug) }}{% else %}{{ TAG_FEED_RSS.format(slug=tag.slug) }}{% endif %}" type="application/rss+xml" rel="alternate" title="{{ tag.slug.title() }} Tag RSS Feed" />
|
||||
{% endif %}
|
||||
{% endblock head %}
|
||||
</head>
|
||||
|
|
|
|||
12
pelican/themes/simple/templates/index.html
vendored
12
pelican/themes/simple/templates/index.html
vendored
|
|
@ -11,11 +11,13 @@
|
|||
<section>{{ article.summary }}</section>
|
||||
<footer>
|
||||
<p>Published: <time datetime="{{ article.date.isoformat() }}"> {{ article.locale_date }} </time></p>
|
||||
<address>By
|
||||
{% for author in article.authors %}
|
||||
<a href="{{ SITEURL }}/{{ author.url }}">{{ author }}</a>
|
||||
{% endfor %}
|
||||
</address>
|
||||
{%- if article.authors %}
|
||||
<address>By
|
||||
{% for author in article.authors %}
|
||||
<a href="{{ SITEURL }}/{{ author.url }}">{{ author }}</a>
|
||||
{% endfor %}
|
||||
</address>
|
||||
{%- endif %}
|
||||
</footer>
|
||||
</article>
|
||||
{% endfor %}
|
||||
|
|
|
|||
2
pelican/themes/simple/templates/page.html
vendored
2
pelican/themes/simple/templates/page.html
vendored
|
|
@ -20,7 +20,7 @@
|
|||
{% import 'translations.html' as translations with context %}
|
||||
{{ translations.translations_for(page) }}
|
||||
|
||||
{{ page.content }}
|
||||
{% block page_content %}{{ page.content }}{% endblock page_content %}
|
||||
|
||||
{% if page.modified %}
|
||||
<footer>
|
||||
|
|
|
|||
|
|
@ -446,13 +446,13 @@ def tumblr2fields(api_key, blogname):
|
|||
slug = post.get("slug") or slugify(title, regex_subs=subs)
|
||||
tags = post.get("tags")
|
||||
timestamp = post.get("timestamp")
|
||||
date = SafeDatetime.fromtimestamp(
|
||||
int(timestamp), tz=datetime.timezone.utc
|
||||
).strftime("%Y-%m-%d %H:%M:%S%z")
|
||||
date = SafeDatetime.fromtimestamp(int(timestamp), tz=datetime.UTC).strftime(
|
||||
"%Y-%m-%d %H:%M:%S%z"
|
||||
)
|
||||
slug = (
|
||||
SafeDatetime.fromtimestamp(
|
||||
int(timestamp), tz=datetime.timezone.utc
|
||||
).strftime("%Y-%m-%d-")
|
||||
SafeDatetime.fromtimestamp(int(timestamp), tz=datetime.UTC).strftime(
|
||||
"%Y-%m-%d-"
|
||||
)
|
||||
+ slug
|
||||
)
|
||||
post_format = post.get("format")
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ def install(path, v=False, u=False):
|
|||
f"or directory in `{theme_path}':\n{e!s}",
|
||||
die=False,
|
||||
)
|
||||
except Exception as e:
|
||||
except OSError as e:
|
||||
err(f"Cannot copy `{path}' to `{theme_path}':\n{e!s}")
|
||||
|
||||
|
||||
|
|
@ -262,7 +262,7 @@ def symlink(path, v=False):
|
|||
print(f"Linking `{path}' to `{theme_path}' ...")
|
||||
try:
|
||||
os.symlink(path, theme_path)
|
||||
except Exception as e:
|
||||
except OSError as e:
|
||||
err(f"Cannot link `{path}' to `{theme_path}':\n{e!s}")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ ssh_upload: publish
|
|||
|
||||
{% set upload = upload + ["sftp_upload"] %}
|
||||
sftp_upload: publish
|
||||
printf 'put -r $(OUTPUTDIR)/*' | sftp $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)
|
||||
printf 'put -r $(OUTPUTDIR)/*' | sftp -P $(SSH_PORT) $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)
|
||||
|
||||
{% set upload = upload + ["rsync_upload"] %}
|
||||
rsync_upload: publish
|
||||
|
|
|
|||
|
|
@ -42,11 +42,18 @@ class URLWrapper:
|
|||
preserve_case=preserve_case,
|
||||
use_unicode=self.settings.get("SLUGIFY_USE_UNICODE", False),
|
||||
)
|
||||
if not self._slug:
|
||||
logger.warning(
|
||||
'Unable to generate valid slug for %s "%s".',
|
||||
self.__class__.__name__,
|
||||
self.name,
|
||||
extra={"limit_msg": "Other invalid slugs."},
|
||||
)
|
||||
return self._slug
|
||||
|
||||
@slug.setter
|
||||
def slug(self, slug):
|
||||
# if slug is expliticly set, changing name won't alter slug
|
||||
# if slug is explicitly set, changing name won't alter slug
|
||||
self._slug_from_name = False
|
||||
self._slug = slug
|
||||
|
||||
|
|
@ -95,7 +102,7 @@ class URLWrapper:
|
|||
return False
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
return self.name or ""
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{type(self).__name__} {self._name!r}>"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,14 @@ import shutil
|
|||
import traceback
|
||||
import unicodedata
|
||||
import urllib
|
||||
from collections.abc import Collection, Generator, Hashable, Iterable, Sequence
|
||||
from collections.abc import (
|
||||
Callable,
|
||||
Collection,
|
||||
Generator,
|
||||
Hashable,
|
||||
Iterable,
|
||||
Sequence,
|
||||
)
|
||||
from contextlib import contextmanager
|
||||
from functools import partial
|
||||
from html import entities
|
||||
|
|
@ -21,7 +28,6 @@ from operator import attrgetter
|
|||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Callable,
|
||||
)
|
||||
|
||||
import dateutil.parser
|
||||
|
|
@ -234,7 +240,7 @@ def get_date(string: str) -> datetime.datetime:
|
|||
|
||||
|
||||
@contextmanager
|
||||
def pelican_open(filename: str, mode: str = "r") -> Generator[str, None, None]:
|
||||
def pelican_open(filename: str, mode: str = "r") -> Generator[str]:
|
||||
"""Open a file and return its content"""
|
||||
|
||||
# utf-8-sig will clear any BOM if present
|
||||
|
|
@ -253,7 +259,7 @@ def slugify(
|
|||
Normalizes string, converts to lowercase, removes non-alpha characters,
|
||||
and converts spaces to hyphens.
|
||||
|
||||
Took from Django sources.
|
||||
Taken from Django sources.
|
||||
|
||||
For a set of sensible default regex substitutions to pass to regex_subs
|
||||
look into pelican.settings.DEFAULT_CONFIG['SLUG_REGEX_SUBSTITUTIONS'].
|
||||
|
|
@ -378,8 +384,8 @@ def clean_output_dir(path: str, retention: Iterable[str]) -> None:
|
|||
if not os.path.isdir(path):
|
||||
try:
|
||||
os.remove(path)
|
||||
except Exception as e:
|
||||
logger.error("Unable to delete file %s; %s", path, e)
|
||||
except Exception:
|
||||
logger.exception("Unable to delete file %s", path)
|
||||
return
|
||||
|
||||
# remove existing content from output folder unless in retention list
|
||||
|
|
@ -393,14 +399,14 @@ def clean_output_dir(path: str, retention: Iterable[str]) -> None:
|
|||
try:
|
||||
shutil.rmtree(file)
|
||||
logger.debug("Deleted directory %s", file)
|
||||
except Exception as e:
|
||||
logger.error("Unable to delete directory %s; %s", file, e)
|
||||
except Exception:
|
||||
logger.exception("Unable to delete directory %s", file)
|
||||
elif os.path.isfile(file) or os.path.islink(file):
|
||||
try:
|
||||
os.remove(file)
|
||||
logger.debug("Deleted file/link %s", file)
|
||||
except Exception as e:
|
||||
logger.error("Unable to delete file %s; %s", file, e)
|
||||
except Exception:
|
||||
logger.exception("Unable to delete file %s", file)
|
||||
else:
|
||||
logger.error("Unable to delete %s, file type unknown", file)
|
||||
|
||||
|
|
@ -795,7 +801,7 @@ def order_content(
|
|||
try:
|
||||
content_list.sort(key=order_by)
|
||||
except Exception:
|
||||
logger.error("Error sorting with function %s", order_by)
|
||||
logger.exception("Error sorting with function %s", order_by)
|
||||
elif isinstance(order_by, str):
|
||||
if order_by.startswith("reversed-"):
|
||||
order_reversed = True
|
||||
|
|
@ -963,7 +969,7 @@ def maybe_pluralize(count: int, singular: str, plural: str) -> str:
|
|||
@contextmanager
|
||||
def temporary_locale(
|
||||
temp_locale: str | None = None, lc_category: int = locale.LC_ALL
|
||||
) -> Generator[None, None, None]:
|
||||
) -> Generator[None]:
|
||||
"""
|
||||
Enable code to run in a context with a temporary locale
|
||||
Resets the locale back when exiting context.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ from pelican.utils import (
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FileOverwriteFailedError(RuntimeError):
|
||||
"""Failed to overwrite an existing file."""
|
||||
|
||||
|
||||
class Writer:
|
||||
def __init__(self, output_path, settings=None):
|
||||
self.output_path = output_path
|
||||
|
|
@ -107,14 +111,20 @@ class Writer:
|
|||
"""
|
||||
if filename in self._overridden_files:
|
||||
if override:
|
||||
raise RuntimeError(f"File {filename} is set to be overridden twice")
|
||||
logger.info("Skipping %s", filename)
|
||||
raise FileOverwriteFailedError(
|
||||
f'Failed to overwrite "{filename}" a second time '
|
||||
"(was previously overwritten)"
|
||||
)
|
||||
logger.info('Skipping "%s", not overwriting', filename)
|
||||
filename = os.devnull
|
||||
elif filename in self._written_files:
|
||||
if override:
|
||||
logger.info("Overwriting %s", filename)
|
||||
logger.info('Overwriting "%s"', filename)
|
||||
else:
|
||||
raise RuntimeError(f"File {filename} is to be overwritten")
|
||||
raise FileOverwriteFailedError(
|
||||
f'Failed to overwrite "{filename}" as Pelican has already '
|
||||
"written to it previously (set `override=True` if intended)"
|
||||
)
|
||||
if override:
|
||||
self._overridden_files.add(filename)
|
||||
self._written_files.add(filename)
|
||||
|
|
@ -161,14 +171,11 @@ class Writer:
|
|||
if path:
|
||||
complete_path = sanitised_join(self.output_path, path)
|
||||
|
||||
try:
|
||||
os.makedirs(os.path.dirname(complete_path))
|
||||
except Exception:
|
||||
pass
|
||||
os.makedirs(os.path.dirname(complete_path), exist_ok=True)
|
||||
|
||||
with self._open_w(complete_path, "utf-8", override_output) as fp:
|
||||
feed.write(fp, "utf-8")
|
||||
logger.info("Writing %s", complete_path)
|
||||
logger.info('Writing "%s"', complete_path)
|
||||
|
||||
signals.feed_written.send(complete_path, context=context, feed=feed)
|
||||
return feed
|
||||
|
|
@ -215,14 +222,11 @@ class Writer:
|
|||
output = template.render(localcontext)
|
||||
path = sanitised_join(output_path, name)
|
||||
|
||||
try:
|
||||
os.makedirs(os.path.dirname(path))
|
||||
except Exception:
|
||||
pass
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
|
||||
with self._open_w(path, "utf-8", override=override) as f:
|
||||
f.write(output)
|
||||
logger.info("Writing %s", path)
|
||||
logger.info('Writing "%s"', path)
|
||||
|
||||
# Send a signal to say we're writing a file with some specific
|
||||
# local context.
|
||||
|
|
|
|||
|
|
@ -14,11 +14,10 @@ classifiers = [
|
|||
"License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Programming Language :: Python :: 3.14",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Content Management System",
|
||||
"Topic :: Internet :: WWW/HTTP :: Site Management",
|
||||
|
|
@ -27,10 +26,10 @@ classifiers = [
|
|||
"Topic :: Text Processing :: Markup :: HTML",
|
||||
"Topic :: Text Processing :: Markup :: reStructuredText",
|
||||
]
|
||||
requires-python = ">=3.9,<4.0"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"blinker>=1.7.0",
|
||||
"docutils>=0.20.1",
|
||||
"docutils>=0.22.0",
|
||||
"feedgenerator>=2.1.0",
|
||||
"jinja2>=3.1.2",
|
||||
"ordered-set>=4.1.0",
|
||||
|
|
@ -59,6 +58,30 @@ pelican-plugins = "pelican.plugins._utils:list_plugins"
|
|||
pelican-quickstart = "pelican.tools.pelican_quickstart:main"
|
||||
pelican-themes = "pelican.tools.pelican_themes:main"
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"BeautifulSoup4>=4.13.3",
|
||||
"jinja2>=3.1.2",
|
||||
"lxml>=4.9.3",
|
||||
"markdown>=3.5.1",
|
||||
"typogrify>=2.1.0",
|
||||
"sphinx>=9.0.0",
|
||||
"sphinxext-opengraph>=0.9.0",
|
||||
"furo==2025.12.19",
|
||||
"livereload>=2.6.3",
|
||||
"psutil>=5.9.6",
|
||||
"pygments>=2.16.1,<2.20.0",
|
||||
"pytest>=7.4.3",
|
||||
"pytest-cov>=4.1.0",
|
||||
"pytest-sugar>=0.9.7",
|
||||
"pytest-xdist>=3.4.0",
|
||||
"tox>=4.11.3",
|
||||
"invoke>=2.2.0",
|
||||
# ruff version should match the one in .pre-commit-config.yaml
|
||||
"ruff==0.12.7",
|
||||
"tomli>=2.0.1; python_version < \"3.11\"",
|
||||
]
|
||||
|
||||
[tool.autopub]
|
||||
project-name = "Pelican"
|
||||
git-username = "botpub"
|
||||
|
|
@ -76,30 +99,6 @@ docserve = "invoke docserve"
|
|||
lint = "invoke lint"
|
||||
test = "invoke tests"
|
||||
|
||||
[tool.pdm.dev-dependencies]
|
||||
dev = [
|
||||
"BeautifulSoup4>=4.13.3",
|
||||
"jinja2>=3.1.2",
|
||||
"lxml>=4.9.3",
|
||||
"markdown>=3.5.1",
|
||||
"typogrify>=2.1.0",
|
||||
"sphinx>=7.1.2",
|
||||
"sphinxext-opengraph>=0.9.0",
|
||||
"furo==2023.9.10",
|
||||
"livereload>=2.6.3",
|
||||
"psutil>=5.9.6",
|
||||
"pygments>=2.16.1,<2.20.0",
|
||||
"pytest>=7.4.3",
|
||||
"pytest-cov>=4.1.0",
|
||||
"pytest-sugar>=0.9.7",
|
||||
"pytest-xdist>=3.4.0",
|
||||
"tox>=4.11.3",
|
||||
"invoke>=2.2.0",
|
||||
# ruff version should match the one in .pre-commit-config.yaml
|
||||
"ruff==0.12.2",
|
||||
"tomli>=2.0.1; python_version < \"3.11\"",
|
||||
]
|
||||
|
||||
[tool.pdm.build]
|
||||
source-includes = [
|
||||
"CONTRIBUTING.rst",
|
||||
|
|
@ -107,6 +106,9 @@ source-includes = [
|
|||
"docs/changelog.rst",
|
||||
"samples/",
|
||||
]
|
||||
excludes = [
|
||||
"pelican/build/"
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["pdm-backend"]
|
||||
|
|
@ -127,7 +129,7 @@ select = [
|
|||
"A", # flake8-builtins
|
||||
"ARG", # flake8-unused-arguments
|
||||
"B", # flake8-bugbear
|
||||
# TODO: "BLE", # flake8-blind-except
|
||||
"BLE", # flake8-blind-except
|
||||
# TODO: Do I want "COM", # flake8-commas
|
||||
"C4", # flake8-comprehensions
|
||||
# TODO: "DJ", # flake8-django
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
sphinx
|
||||
sphinxext-opengraph
|
||||
furo==2023.9.10
|
||||
furo==2025.12.19
|
||||
livereload
|
||||
matplotlib
|
||||
tomli;python_version<"3.11"
|
||||
|
|
|
|||
3
tasks.py
3
tasks.py
|
|
@ -3,7 +3,6 @@ from pathlib import Path
|
|||
from shutil import which
|
||||
|
||||
from invoke import task
|
||||
from livereload import Server
|
||||
|
||||
PKG_NAME = "pelican"
|
||||
PKG_PATH = Path(PKG_NAME)
|
||||
|
|
@ -30,6 +29,8 @@ def docbuild(c):
|
|||
@task(docbuild)
|
||||
def docserve(c):
|
||||
"""Serve docs at http://localhost:$DOCS_PORT/ (default port is 8000)"""
|
||||
from livereload import Server # noqa: PLC0415
|
||||
|
||||
server = Server()
|
||||
server.watch("docs/conf.py", lambda: docbuild(c))
|
||||
server.watch("CONTRIBUTING.rst", lambda: docbuild(c))
|
||||
|
|
|
|||
5
tox.ini
5
tox.ini
|
|
@ -1,13 +1,12 @@
|
|||
[tox]
|
||||
envlist = py{3.9,3.10,3.11,3.12,3.13},docs
|
||||
envlist = py{3.11,3.12,3.13,3.14},docs
|
||||
|
||||
[testenv]
|
||||
basepython =
|
||||
py3.9: python3.9
|
||||
py3.10: python3.10
|
||||
py3.11: python3.11
|
||||
py3.12: python3.12
|
||||
py3.13: python3.13
|
||||
py3.14: python3.14
|
||||
passenv = *
|
||||
usedevelop=True
|
||||
deps =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue