-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #68 from stuartmaxwell:plugin_system_mvp
Plugin_system_mvp
- Loading branch information
Showing
18 changed files
with
936 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Example Plugin for DJ Press |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[project] | ||
name = "djpress-example-plugin" | ||
version = "0.1.0" | ||
description = "Example plugin for DJ Press" | ||
readme = "README.md" | ||
authors = [{ name = "Stuart Maxwell", email = "[email protected]" }] | ||
requires-python = ">=3.10" | ||
dependencies = ["django>=4.2.0", "djpress"] | ||
|
||
[build-system] | ||
requires = ["hatchling"] | ||
build-backend = "hatchling.build" | ||
|
||
[tool.uv.sources] | ||
djpress = { workspace = true } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""DJ Press example plugin.""" |
46 changes: 46 additions & 0 deletions
46
djpress-example-plugin/src/djpress_example_plugin/plugin.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
"""An example DJ Press plugin.""" | ||
|
||
from djpress.plugins import DJPressPlugin, PluginRegistry | ||
|
||
|
||
class Plugin(DJPressPlugin): | ||
"""An example DJ Press plugin.""" | ||
|
||
name = "djpress_example_plugin" | ||
|
||
def setup(self, registry: PluginRegistry) -> None: | ||
"""Set up the plugin. | ||
Args: | ||
registry (Hooks): The plugin registry. | ||
""" | ||
registry.register_hook("pre_render_content", self.add_greeting) | ||
registry.register_hook("post_render_content", self.add_goodbye) | ||
|
||
def add_greeting(self, content: str) -> str: | ||
"""Add a greeting to the content. | ||
This is a pre-render hook, so the content is still in Markdown format. | ||
Args: | ||
content (str): The content to modify. | ||
Returns: | ||
str: The modified content. | ||
""" | ||
return f"{self.config.get("pre_text")} This was added by `djpress_example_plugin`!\n\n---\n\n{content}" | ||
|
||
def add_goodbye(self, content: str) -> str: | ||
"""Add a goodbye message to the content. | ||
This is a post-render hook, so the content has already been rendered from Markdown to HTML. | ||
Args: | ||
content (str): The content to modify. | ||
Returns: | ||
str: The modified content. | ||
""" | ||
return ( | ||
f"{content}<hr><p>{self.config.get("pre_text")} This was added by <code>djpress_example_plugin</code>!</p>" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
# Plugins | ||
|
||
DJ Press includes a plugin system that allows you to extend its functionality. Plugins can modify content before and | ||
after rendering, and future versions will include more hook points for customization. | ||
|
||
## Creating a Plugin | ||
|
||
To create a plugin, create a new Python package with the following structure: | ||
|
||
```text | ||
djpress_my_plugin/ | ||
__init__.py | ||
plugin.py | ||
``` | ||
|
||
In `plugin.py`, create a class called `Plugin` that inherits from `DJPressPlugin`: | ||
|
||
```python | ||
from djpress.plugins import DJPressPlugin | ||
|
||
class Plugin(DJPressPlugin): | ||
name = "djpress_my_plugin" # Required - recommended to be the same as the package name | ||
|
||
def setup(self, registry): | ||
# Register your hook callbacks | ||
registry.register_hook("pre_render_content", self.modify_content) | ||
registry.register_hook("post_render_content", self.modify_html) | ||
|
||
def modify_content(self, content: str) -> str: | ||
"""Modify the markdown content before rendering.""" | ||
# Create your code here... | ||
return content | ||
|
||
def modify_html(self, content: str) -> str: | ||
"""Modify the HTML after rendering.""" | ||
# Create your code here... | ||
return content | ||
``` | ||
|
||
## Available Hooks | ||
|
||
Currently available hooks: | ||
|
||
- `pre_render_content`: Called before markdown content is rendered to HTML | ||
- `post_render_content`: Called after markdown content is rendered to HTML | ||
|
||
**Note** that you can also import the `Hooks` enum class, and reference the hook names specifically, e.g. | ||
`from djpress.plugins import Hooks` and then you can refer to the above two hooks as follows: | ||
|
||
- `Hooks.PRE_RENDER_CONTENT` | ||
- `Hooks.POST_RENDER_CONTENT` | ||
|
||
Each hook receives the content as its first argument and must return the modified content. | ||
|
||
## Installing Plugins | ||
|
||
- Install your plugin package: | ||
|
||
```bash | ||
pip install djpress-my-plugin | ||
``` | ||
|
||
- Add the plugin to your DJ Press settings by adding the package name of your plugin to the `PLUGINS` key in `DJPRESS_SETTINGS`. | ||
If you use the recommended file structure for your plugin as described above, you only need the package name, | ||
i.e. this assumes your plugin code resides in a class called `Plugin` in a module called `plugins.py` | ||
|
||
```python | ||
DJPRESS_SETTINGS = { | ||
"PLUGINS": [ | ||
"djpress_my_plugin" | ||
], | ||
} | ||
``` | ||
|
||
- If you have a more complex plugin or you prefer a different style of packaging your plugin, you must use the full | ||
path to your plugin class. For example, if your package name is `djpress_my_plugin` and the module with your plugin | ||
class is `custom.py` and the plugin class is called `MyPlugin`, you'd need to use the following format: | ||
|
||
```python | ||
DJPRESS_SETTINGS = { | ||
"PLUGINS": [ | ||
"djpress_my_plugin.custom.MyPlugin" | ||
], | ||
} | ||
``` | ||
|
||
## Plugin Configuration | ||
|
||
Plugins can receive configuration through the `PLUGIN_SETTINGS` dictionary. Access settings in your plugin using `self.config`. | ||
|
||
For example, here is the `PLUGIN_SETTINGS` from the example plugin in this repository. **Note** that the dictionary key | ||
is the `name` of the plugin and not the package name. It's recommended to keep the `name` of the plugin the same as the | ||
package name, otherwise it will get confusing. | ||
|
||
```python | ||
DJPRESS_SETTINGS = { | ||
"PLUGINS": ["djpress_example_plugin"], # this is the package name! | ||
"PLUGIN_SETTINGS": { | ||
"djpress_example_plugin": { # this is the plugin name! | ||
"pre_text": "Hello, this text is configurable!", | ||
"post_text": "Goodbye, this text is configurable!", | ||
}, | ||
}, | ||
} | ||
``` | ||
|
||
In your plugin, you can access these settings using `self.config.get("pre_text")` or `self.config.get("post_text")`. | ||
|
||
## Plugin Development Guidelines | ||
|
||
1. You must define a unique `name` for your plugin and strongly recommend this is the same as the package name. | ||
2. Handle errors gracefully - don't let your plugin break the site. | ||
3. Use type hints for better code maintainability. | ||
4. Include tests for your plugin's functionality. | ||
5. Document any settings your plugin uses. | ||
|
||
## System Checks | ||
|
||
DJ Press includes system checks that will warn about: | ||
|
||
- Unknown hooks (might indicate deprecated hooks or version mismatches) | ||
|
||
Run Django's check framework to see any warnings: | ||
|
||
```bash | ||
python manage.py check | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
"""djpress module.""" | ||
|
||
__version__ = "0.11.4" | ||
__version__ = "0.12.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
"""Custom checks for DJPress.""" | ||
|
||
from django.core.checks import Warning | ||
|
||
|
||
def check_plugin_hooks(app_configs, **kwargs) -> list[Warning]: # noqa: ANN001, ANN003, ARG001 | ||
"""Check for unknown plugin hooks.""" | ||
from djpress.plugins import Hooks, registry | ||
|
||
# Ensure plugins are loaded | ||
if not registry._loaded: # noqa: SLF001 | ||
registry.load_plugins() | ||
|
||
warnings = [] | ||
|
||
for hook_name in registry.hooks: | ||
if not isinstance(hook_name, Hooks): | ||
warning = Warning( | ||
f"Plugin registering unknown hook '{hook_name}'.", | ||
hint=("This might indicate use of a deprecated hook or a hook from a newer version of DJPress."), | ||
obj=hook_name, | ||
id="djpress.W001", | ||
) | ||
warnings.append(warning) | ||
|
||
return warnings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.