插件¶
从3.0版开始,Pelican支持插件。插件是一种向Pelican添加特性而不必直接修改Pelican核心的方法。
如何使用插件¶
从4.5版开始,Pelican迁移到了一个新的插件结构中,利用命名空间包,可以很容易地通过 Pip. 支持此结构的插件将安装在命名空间包下 pelican.plugins
它可以被鹈鹕自动发现。要查看在您的环境中处于活动状态的Pip安装的命名空间插件的列表,请运行:
pelican-plugins
如果你离开 PLUGINS
设置为默认值 (None
),Pelican将自动发现命名空间插件并注册它们。另一方面,如果指定 PLUGINS
设置为插件列表,此自动发现将被禁用。此时,只注册您指定的插件,并且您必须显式列出任何命名空间插件。
如果您正在使用 PLUGINS
设置时,可以用两种方式指定插件。第一个方法将插件指定为字符串列表。命名空间插件可以通过其全名指定 (pelican.plugins.myplugin
)或者他们的简称 (myplugin
):
PLUGINS = ['package.myplugin',
'namespace_plugin1',
'pelican.plugins.namespace_plugin2']
或者,您可以将它们导入设置文件并传递模块:
from package import myplugin
from pelican.plugins import namespace_plugin1, namespace_plugin2
PLUGINS = [myplugin, namespace_plugin1, namespace_plugin2]
注解
当尝试使用不同的插件(尤其是那些处理元数据和内容的插件)时,缓存可能会产生干扰,并且更改可能不可见。在这种情况下,使用禁用缓存 LOAD_CONTENT_CACHE = False
或者使用 --ignore-cache
命令行开关。
如果插件不在可导入路径中,则可以通过 PLUGIN_PATHS
设置。如以下示例所示,中的路径 PLUGIN_PATHS
列表可以是绝对的,也可以是相对于设置文件的:
PLUGIN_PATHS = ["plugins", "/srv/pelican/plugins"]
PLUGINS = ["assets", "liquid_tags", "sitemap"]
在哪里可以找到插件¶
命名空间插件可以在 pelican-plugins organization 作为单独的存储库。旧插件位于 pelican-plugins repository 并将逐步淘汰,取而代之的是命名空间版本。
请注意,虽然我们尽力检查和维护这些插件,但它们是由Pelican社区提交的,因此可能具有不同级别的支持和互操作性。
如何创建插件¶
插件基于信号的概念。鹈鹕发送信号,插件订阅这些信号。可用信号列表将在后续章节中记录。
插件要遵循的唯一规则是定义 register
可调用的,其中你可以将信号映射到你的插件逻辑。举个简单的例子:
import logging
from pelican import signals
log = logging.getLogger(__name__)
def test(sender):
log.debug("%s initialized !!", sender)
def register():
signals.initialized.connect(test)
注解
信号接收器被弱引用,因此不能在 register
否则它们将在信号发出之前被垃圾回收。
如果多个插件连接到同一信号,则无法保证或控制插件的执行顺序。这是继承自 Blinker, 鹈鹕用来实现信号的依赖关系。
命名空间插件结构¶
命名空间插件必须遵循特定的结构才能正常工作。它们需要是可安装的(即包含 setup.py
或等效文件)并具有如下文件夹结构:
myplugin
├── pelican
│ └── plugins
│ └── myplugin
│ ├── __init__.py
│ └── ...
├── ...
└── setup.py
至关重要的是 pelican
或 pelican/plugins
文件夹 not 包含一个 __init__.py
文件。事实上,除了上述结构中列出的文件夹之外,最好将这些文件夹清空,并将与插件相关的文件单独包含在 pelican/plugins/myplugin
文件夹以避免任何问题。
为了方便地设置适当的结构,a cookiecutter template for plugins 提供。有关如何使用它的说明,请参阅该项目的自述文件。
信号一览表¶
以下是当前实施的信号列表:
信号 |
争论 |
描述 |
---|---|---|
已初始化 |
Pelican物体 |
|
定稿 |
Pelican物体 |
在执行所有生成器之后,在pelican退出之前调用,这对于自定义后处理操作非常有用,例如:-缩小js/css资产。-使用更新的网站地图通知/ping搜索引擎。 |
generator_init |
生成器 |
在中调用 Generator.__init__ |
all_generators_finalized |
生成器 |
在执行所有生成器之后和写入输出之前调用 |
readers_init |
读者 |
在中调用 Readers.__init__ |
article_generator_context |
项目生成器,元数据 |
|
article_generator_preread |
article_generator |
在读入文章之前调用ArticlesGenerator.generate_上下文;如果代码需要在解析每个项目之前执行某些操作,则使用 |
article_generator_init |
article_generator |
在中调用 ArticlesGenerator.__init__ |
article_generator_pretaxonomy |
article_generator |
在创建类别和标记列表之前调用,当修改要生成的项目列表以便删除的项目不会在类别或标记中泄漏时非常有用 |
article_generator_finalized |
article_generator |
在结束时调用ArticlesGenerator.generate_上下文 |
article_generator_write_article |
文章生成器,内容 |
在编写每个文章之前调用,文章作为内容传递 |
article_writer_finalized |
文章生成器,作者 |
在编写完所有文章和相关页面之后,但在关闭项目生成器之前调用。 |
get_generators |
Pelican物体 |
在中调用Pelican.get_generator_类,可以返回一个生成器,或元组或列表中的多个生成器。 |
get_writer |
Pelican物体 |
在中调用Pelican。get嫒作家,可以返回自定义写入程序。 |
page_generator_context |
页面生成器,元数据 |
|
page_generator_preread |
page_generator |
在读入页之前调用PageGenerator.generate_上下文;如果代码需要在解析每个页面之前执行某些操作,则使用。 |
page_generator_init |
page_generator |
在中调用 PagesGenerator.__init__ |
page_generator_finalized |
page_generator |
在结束时调用PagesGenerator.generate_上下文 |
page_generator_write_page |
页面生成器,内容 |
在编写每个页面之前调用,页面作为内容传递 |
page_writer_finalized |
page_生成器,作者 |
在写入所有页之后,但在页生成器关闭之前调用。 |
static_generator_context |
静态_生成器,元数据 |
|
static_generator_preread |
static_generator |
在读入静态文件之前调用StaticGenerator.generate_上下文;如果代码需要在将每个静态文件添加到staticfiles列表之前执行某些操作,则使用。 |
static_generator_init |
static_generator |
在中调用 StaticGenerator.__init__ |
static_generator_finalized |
static_generator |
在结束时调用StaticGenerator.generate_上下文 |
content_object_init |
content_object |
在结束时调用 Content.__init__ |
content_written |
路径,上下文 |
每次写入内容文件时调用。 |
feed_generated |
上下文,提要 |
每次生成提要时调用。可用于在写入提要对象之前对其进行修改。 |
feed_written |
路径、上下文、提要 |
每次写入提要文件时调用。 |
警告
避免 content_object_init
如果你想读就发信号 summary
或 content
内容对象的属性。可能导致无法解决的链接 链接到内部内容 (见 pelican-plugins bug #314 )使用 _summary
和 _content
属性,或者在以后运行插件(例如。 all_generators_finalized
)
注解
Pelican3.2之后,信号名称被标准化。旧插件可能需要更新才能使用新名称:
旧名 |
新名称 |
---|---|
article_generate_context |
article_generator_context |
article_generate_finalized |
article_generator_finalized |
article_generate_preread |
article_generator_preread |
pages_generate_context |
page_generator_context |
pages_generate_preread |
page_generator_preread |
pages_generator_finalized |
page_generator_finalized |
pages_generator_init |
page_generator_init |
static_generate_context |
static_generator_context |
static_generate_preread |
static_generator_preread |
食谱¶
我们最终意识到创建插件的一些方法最好在文档中的某个地方共享,所以它们就在这里!
如何创建新的阅读器¶
您可能希望添加对自己的输入格式的支持。虽然在Pelican core中添加这个特性是有意义的,但是我们明智地选择了避免这种情况,而是通过插件定义不同的阅读器。
这种选择背后的基本原理主要是插件确实很容易编写,并且当插件不活动时不会减慢Pelican本身的速度。
别再说了-这里有个例子:
from pelican import signals
from pelican.readers import BaseReader
# Create a new reader class, inheriting from the pelican.reader.BaseReader
class NewReader(BaseReader):
enabled = True # Yeah, you probably want that :-)
# The list of file extensions you want this reader to match with.
# If multiple readers were to use the same extension, the latest will
# win (so the one you're defining here, most probably).
file_extensions = ['yeah']
# You need to have a read method, which takes a filename and returns
# some content and the associated metadata.
def read(self, filename):
metadata = {'title': 'Oh yeah',
'category': 'Foo',
'date': '2012-12-01'}
parsed = {}
for key, value in metadata.items():
parsed[key] = self.process_metadata(key, value)
return "Some content", parsed
def add_reader(readers):
readers.reader_classes['yeah'] = NewReader
# This is how pelican works.
def register():
signals.readers_init.connect(add_reader)
添加新生成器¶
添加一个新的生成器也非常容易。你可能想看看 Pelican内部构件 有关如何创建自己的生成器的详细信息。
def get_generators(pelican_object):
# define a new generator here if you need to
return MyGenerator
def register():
signals.get_generators.connect(get_generators)
添加新编写器¶
添加编写器将允许您将其他文件格式输出到磁盘,或更改现有格式写入磁盘的方式。请注意,一次只有一个编写器处于活动状态,因此请确保将内置编写器子类化为子类,或者完全重新实现它。
以下是如何设置您自己的编写器的基本示例:
from pelican.writers import Writer
from pelican import signals
class MyWriter(Writer):
# define new writer functionality
pass
def add_writer(pelican_object):
# use pelican_instance to setup stuff if needed
return MyWriter
def register():
signals.get_writer.connect(add_writer)