-
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.
* refactor SomePerson class into a "framework" class
* update seo framework plugin to account for use of pelican.plugins.sitemap
- Loading branch information
1 parent
86b3742
commit 7c0f378
Showing
13 changed files
with
224 additions
and
184 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
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,143 +1,25 @@ | ||
from functools import cached_property | ||
from secrets import choice | ||
|
||
from pelican import Pelican, signals | ||
from pydantic import BaseModel | ||
|
||
from someperson.plugins.base import Plugin, PluginHandler | ||
from someperson.plugins.markdown import MarkdownPlugin | ||
from someperson.plugins.seo import SeoPlugin | ||
from someperson.plugins.theme import ThemePlugin | ||
|
||
|
||
class SocialAccount(BaseModel): | ||
username: str | ||
link_format: str | ||
|
||
@property | ||
def link(self) -> str: | ||
return self.link_format.format(username=self.username) | ||
|
||
|
||
class Twitter(SocialAccount): | ||
link_format: str = "https://twitter.com/{username}" | ||
|
||
|
||
class Link(BaseModel): | ||
title: str | ||
href: str | ||
|
||
|
||
class Author(BaseModel): | ||
first_names: list[str] | ||
last_names: list[str] | ||
twitter: Twitter | ||
|
||
@property | ||
def name_parts(self) -> tuple[str, str]: | ||
return self.first_names[0] or "", self.last_names[0] or "" | ||
|
||
@property | ||
def name(self) -> str: | ||
first, last = self.name_parts | ||
return f"{first} {last}".strip() | ||
|
||
@property | ||
def rand_name_parts(self) -> tuple[str, str]: | ||
return choice(self.first_names) or "", choice(self.last_names[0]) or "" | ||
|
||
@property | ||
def names(self) -> dict[str, list[str]]: | ||
return {"first": self.first_names, "last": self.last_names} | ||
|
||
|
||
class Palette(BaseModel): | ||
id: str | ||
icon: str | ||
name: str | ||
emojis: list[str] = [] | ||
|
||
@property | ||
def serialized(self) -> dict[str, str]: | ||
return self.model_dump() | ||
|
||
|
||
class Theme(BaseModel): | ||
palettes: list[Palette] | ||
default_palette_id: str | ||
hash: str = "" | ||
|
||
@cached_property | ||
def default_palette(self) -> Palette: | ||
palettes = {p.id: p for p in self.palettes} | ||
if default := palettes.get(self.default_palette_id): | ||
return default | ||
err = f"No palette for default ID '{self.default_palette_id}'." | ||
raise ValueError(err) | ||
|
||
|
||
class SomePersonConfig(BaseModel): | ||
author: Author | ||
description: str | ||
theme: Theme | ||
menu: list[Link] = [] | ||
plugins: list[Plugin] | ||
|
||
|
||
class SomePerson: | ||
_supported_plugins: tuple[type[Plugin], ...] = (ThemePlugin, MarkdownPlugin, SeoPlugin) | ||
_supported_signals: tuple[str, ...] = ("initialized", "content_written", "generator_init") | ||
|
||
def __init__( | ||
self, | ||
*, | ||
pelican_signal=signals, | ||
settings_key: str = "SOME_PERSON", | ||
) -> None: | ||
self.settings_key = settings_key | ||
self.signals = pelican_signal | ||
|
||
self.theme_config: SomePersonConfig | None = None | ||
self._pelican_settings = None | ||
|
||
def receiver(signal_name: str, handler: PluginHandler): | ||
def _reciever(*args, **kwargs): | ||
if (method := getattr(handler, f"sig_{signal_name}", None)) and handler.config.enabled: | ||
method(*args, **kwargs) | ||
|
||
return _reciever | ||
|
||
self._handlers: dict[str, PluginHandler] = {} | ||
for plugin_cls in self._supported_plugins: | ||
plugin = plugin_cls() | ||
hcls = plugin_cls.handler | ||
self._handlers[plugin_cls.__name__] = hcls(plugin) | ||
|
||
for signal_name in self._supported_signals: | ||
setattr( | ||
self, | ||
f"_r_{hcls.__name__}_{signal_name}", | ||
receiver(signal_name, self._handlers[plugin_cls.__name__]), | ||
) | ||
|
||
def _r_initialized(self, app: Pelican) -> bool: | ||
self.theme_config = app.settings.get(self.settings_key) | ||
self._pelican_settings = app.settings | ||
for plugin in self.theme_config.plugins: | ||
self._handlers[type(plugin).__name__].connect(self._pelican_settings, self.theme_config, plugin) | ||
|
||
def register(self) -> None: | ||
self.signals.initialized.connect(self._r_initialized) | ||
for handler in self._handlers.values(): | ||
for signal_name in self._supported_signals: | ||
if (method := getattr(self, f"_r_{type(handler).__name__}_{signal_name}", None)) and ( | ||
signal := getattr(self.signals, signal_name, None) | ||
): | ||
signal.connect(method) | ||
|
||
|
||
some_person = SomePerson() | ||
from pelican.plugins.signals import content_written, finalized, generator_init, initialized | ||
|
||
from someperson.configuration import ( # noqa: F401 | ||
Author, | ||
Configuration, | ||
Link, | ||
Palette, | ||
Theme, | ||
Twitter, | ||
) | ||
from someperson.framework import Framework | ||
|
||
framework = Framework( | ||
supported_signals=( | ||
initialized, | ||
content_written, | ||
generator_init, | ||
finalized, | ||
), | ||
settings_key="SOME_PERSON", | ||
) | ||
|
||
|
||
def register() -> None: | ||
some_person.register() | ||
framework.configure() |
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,85 @@ | ||
from functools import cached_property | ||
from secrets import choice | ||
|
||
from pydantic import BaseModel | ||
|
||
from someperson.plugins.base import Plugin | ||
|
||
|
||
class StaticManifest(BaseModel): | ||
hash: str | ||
youtube_use_list: bool | ||
|
||
|
||
class SocialAccount(BaseModel): | ||
username: str | ||
link_format: str | ||
|
||
@property | ||
def link(self) -> str: | ||
return self.link_format.format(username=self.username) | ||
|
||
|
||
class Twitter(SocialAccount): | ||
link_format: str = "https://twitter.com/{username}" | ||
|
||
|
||
class Link(BaseModel): | ||
title: str | ||
href: str | ||
|
||
|
||
class Author(BaseModel): | ||
first_names: list[str] | ||
last_names: list[str] | ||
twitter: Twitter | ||
|
||
@property | ||
def name_parts(self) -> tuple[str, str]: | ||
return self.first_names[0] or "", self.last_names[0] or "" | ||
|
||
@property | ||
def name(self) -> str: | ||
first, last = self.name_parts | ||
return f"{first} {last}".strip() | ||
|
||
@property | ||
def rand_name_parts(self) -> tuple[str, str]: | ||
return choice(self.first_names) or "", choice(self.last_names[0]) or "" | ||
|
||
@property | ||
def names(self) -> dict[str, list[str]]: | ||
return {"first": self.first_names, "last": self.last_names} | ||
|
||
|
||
class Palette(BaseModel): | ||
id: str | ||
icon: str | ||
name: str | ||
emojis: list[str] = [] | ||
|
||
@property | ||
def serialized(self) -> dict[str, str]: | ||
return self.model_dump() | ||
|
||
|
||
class Theme(BaseModel): | ||
palettes: list[Palette] | ||
default_palette_id: str | ||
hash: str = "" | ||
|
||
@cached_property | ||
def default_palette(self) -> Palette: | ||
palettes = {p.id: p for p in self.palettes} | ||
if default := palettes.get(self.default_palette_id): | ||
return default | ||
err = f"No palette for default ID '{self.default_palette_id}'." | ||
raise ValueError(err) | ||
|
||
|
||
class Configuration(BaseModel): | ||
author: Author | ||
description: str | ||
theme: Theme | ||
menu: list[Link] = [] | ||
plugins: list[Plugin] |
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,51 @@ | ||
from collections.abc import Sequence | ||
from typing import TYPE_CHECKING | ||
|
||
from blinker import NamedSignal | ||
from pelican import Pelican | ||
|
||
if TYPE_CHECKING: | ||
from someperson.configuration import Configuration | ||
|
||
from someperson.plugins.base import PluginHandler | ||
from someperson.utils import Settings, get_signal_name | ||
|
||
|
||
class Framework: | ||
@staticmethod | ||
def receiver_name(signal: NamedSignal) -> str: | ||
name = get_signal_name(signal) | ||
return f"_receiver_for_{name}" | ||
|
||
def __init__(self, *, supported_signals: Sequence[NamedSignal], settings_key: str) -> None: | ||
self._settings_key = settings_key | ||
self._supported_signals: dict[str, NamedSignal] = { | ||
get_signal_name(signal): signal for signal in supported_signals | ||
} | ||
self.framework_config: Configuration | None = None | ||
self.pelican_config: Settings | None = None | ||
self.plugins: list[PluginHandler] = [] | ||
|
||
for signal in self._supported_signals.values(): | ||
setattr(self, Framework.receiver_name(signal), self._receiver_factory(signal)) | ||
|
||
def configure(self) -> None: | ||
self._supported_signals["initialized"].connect(self._signal_initialized) | ||
for signal in self._supported_signals.values(): | ||
if method := getattr(self, Framework.receiver_name(signal), None): | ||
signal.connect(method) | ||
|
||
def _signal_initialized(self, app: Pelican) -> None: | ||
self.pelican_config = app.settings | ||
self.framework_config = app.settings.get(self._settings_key) | ||
for plugin in self.framework_config.plugins: | ||
handler = plugin.handler(plugin, self.pelican_config, self.framework_config) | ||
self.plugins.append(handler) | ||
|
||
def _receiver_factory(self, signal: NamedSignal): | ||
def receiver(*args, **kwargs) -> None: | ||
for handler in self.plugins: | ||
if (method := getattr(handler, PluginHandler.receiver_name(signal), None)) and handler.config.enabled: | ||
method(*args, **kwargs) | ||
|
||
return receiver |
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,3 @@ | ||
from someperson.plugins.markdown import MarkdownPlugin # noqa: F401 | ||
from someperson.plugins.seo import SeoPlugin # noqa: F401 | ||
from someperson.plugins.theme import ThemePlugin # noqa: F401 |
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
Oops, something went wrong.