Skip to content

Commit

Permalink
pushes plugins to site building
Browse files Browse the repository at this point in the history
  • Loading branch information
kjaymiller committed Jun 2, 2023
1 parent c181c42 commit 4bc2ea1
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 42 deletions.
16 changes: 14 additions & 2 deletions src/render_engine/_base_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from slugify import slugify

from .hookspecs import register_plugins


class BaseObject:
"""
Expand All @@ -14,6 +16,7 @@ class BaseObject:

title: str
template_vars: dict
plugins: list

@property
def _title(self) -> str:
Expand Down Expand Up @@ -71,7 +74,16 @@ def to_dict(self):
if hasattr(self, "template_vars"):
for key, value in self.template_vars.items():
base_dict[key] = value

base_dict.pop("template_vars")

return base_dict


def register_plugins(self, plugins):
"""Creates the plugin manager and registers plugins"""

if getattr('self', 'plugins', None):
self.plugins.extend(plugins)
else:
self.plugins = plugins

self._pm = register_plugins(self.plugins)
17 changes: 9 additions & 8 deletions src/render_engine/blog.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
from .collection import Collection
from .feeds import RSSFeed
from .page import Page
from .parsers.markdown import MarkdownPageParser


class BlogPost(Page):
"""Page Like object with slight modifications to work with BlogPosts."""
invalid_attrs = ["slug"]


class Blog(Collection):
"""
Custom :py:class:`collection.Collection` class with archiving enabled, sort by `date` by default.
Todos:
TODOS:
- Add Support for JSON Feeds
- Rename the archive items so they are not private
"""

BasePageParser = MarkdownPageParser
content_type: BlogPost = BlogPost
sort_reverse: bool = True
sort_by = "date"
has_archive = True
Feed = RSSFeed

def latest(self, count: int = 1):
"""Get the latest post from the collection."""
latest_pages = list(sorted(
self.__iter__(),
key=lambda x:getattr(x, self.sort_by),
reverse=self.sort_reverse))[0:count]
return latest_pages
7 changes: 3 additions & 4 deletions src/render_engine/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ class BasicCollection(Collection):

def __init__(
self,
plugins: list[typing.Callable] = [],
) -> None:

self.has_archive = any(
Expand All @@ -81,8 +80,6 @@ def __init__(
getattr(self, "items_per_page", None),
]
)
self.plugins = [*getattr(self, "plugins", []), *plugins]
self.PM = register_plugins(plugins=self.plugins)
self.title = self._title

def iter_content_path(self):
Expand Down Expand Up @@ -122,8 +119,10 @@ def get_page(
_page = self.content_type(
content_path=content_path,
Parser=self.PageParser,
plugins=self.plugins,
)

if getattr(self, '_pm', None):
_page.register_plugins(self.plugins)
_page.parser_extras = getattr(self, "parser_extras", {})
_page.routes = self.routes
_page.template = getattr(self, "template", None)
Expand Down
9 changes: 0 additions & 9 deletions src/render_engine/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import jinja2

from ._base_object import BaseObject
from .hookspecs import register_plugins
from .parsers.base_parsers import BasePageParser


Expand Down Expand Up @@ -126,9 +125,6 @@ class Page(BasePage):
template:
The template used to render the page.
If not provided, the `Site`'s `content` will be used.
invalid_attrs:
A list of attributes that are not valid for the page.
Defaults to `["slug", "content"]`. See [Invalid Attrs][invalid-attrs].
Parser:
The parser to generate the page's `raw_content`.
Defaults to `BasePageParser`.
Expand Down Expand Up @@ -169,11 +165,6 @@ def __init__(
for key, val in attrs.items():
setattr(self, key.lower(), val)

# Set the plugins
self.plugins = [*getattr(self, "plugins", []), *plugins]
self.PM = register_plugins(self.plugins)
self.PM.hook.render_content(Page=self) # type: ignore pluggy doesn't expose hook

@property
def _content(self):
"""Returns the content of the page."""
Expand Down
23 changes: 14 additions & 9 deletions src/render_engine/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(
self,
plugins: list[str] = [],
) -> None:
self._route_list = dict()
self.route_list = dict()
self.subcollections = defaultdict(lambda: {"pages": []})
self.engine.globals.update(self.site_vars)
self.plugins = [*plugins, *getattr(self, "plugins", [])]
Expand Down Expand Up @@ -82,9 +82,10 @@ class Posts(Collection):
site.collection(Posts) # also works
```
"""
_Collection = Collection(plugins=self.plugins)
_Collection = Collection()
_Collection.register_plugins(self.plugins)
self._pm.hook.pre_build_collection(collection=_Collection) #type: ignore
self._route_list[_Collection._slug] = _Collection
self.route_list[_Collection._slug] = _Collection
return _Collection

def page(self, Page: Page) -> Page:
Expand Down Expand Up @@ -113,10 +114,10 @@ class About(Page):
site.page(About) # also works
```
"""
page = Page(plugins=self.plugins)
page = Page()
page.title = page._title # Expose _title to the user through `title`
self._route_list[getattr(page, page._reference)] = page
return page
page.register_plugins(self.plugins)
self.route_list[getattr(page, page._reference)] = page

def _render_static(self) -> None:
"""Copies a Static Directory to the output folder"""
Expand All @@ -141,6 +142,7 @@ def _render_output(self, route: str, page: type[Page]):
def _render_partial_collection(self, collection: Collection) -> None:
"""Iterate through the Changed Pages and Check for Collections and Feeds"""
for entry in collection._generate_content_from_modified_pages():
entry._pm.hook.render_content(Page=entry)
for route in collection.routes:
self._render_output(route, entry)

Expand All @@ -157,6 +159,7 @@ def _render_full_collection(self, collection: Collection) -> None:
"""Iterate through Pages and Check for Collections and Feeds"""

for entry in collection:
entry._pm.hook.render_content(Page=entry)
for route in collection.routes:
self._render_output(route, entry)

Expand Down Expand Up @@ -190,19 +193,21 @@ def render(self) -> None:

# Parse Route List
task_add_route = progress.add_task(
"[blue]Adding Routes", total=len(self._route_list)
"[blue]Adding Routes", total=len(self.route_list)
)

if pathlib.Path(self.static_path).exists():
self._render_static()
self.engine.globals["site"] = self
self.engine.globals["routes"] = self._route_list
self.engine.globals["routes"] = self.route_list

for slug, entry in self._route_list.items():
for slug, entry in self.route_list.items():
progress.update(
task_add_route, description=f"[blue]Adding[gold]Route: [blue]{slug}"
)
if isinstance(entry, Page):
if getattr(entry, "collection", None):
entry._pm.hook.render_content(Page=entry)
for route in entry.routes:
progress.update(
task_add_route,
Expand Down
1 change: 1 addition & 0 deletions tests/test_base_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def test_base_object_to_dict_with_template_vars(self):
"slug": "testobject",
"url": None,
"test": "test",
'template_vars': {'test': 'test'},
}

assert self.test_object.template_vars == {"test": "test"}
4 changes: 2 additions & 2 deletions tests/test_feeds.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ class BasicCollection(Collection):

def test_rss_feed_item_url(site):
"""Test that the feed item url is set correctly"""
assert "<link>http://localhost:8000/page.html</link>" in site._route_list['testcollection']._feed._render_content(engine=site.engine, SITE_URL="http://localhost:8000")
assert "<link>http://localhost:8000/page.html</link>" in site.route_list['testcollection']._feed._render_content(engine=site.engine, SITE_URL="http://localhost:8000")



def test_rss_feed_item_has_guid(site):
"""Test that the feed item url is set correctly"""
assert '<guid isPermaLink="true">http://localhost:8000/page.html</guid>' in site._route_list['testcollection']._feed._render_content(engine=site.engine, SITE_URL="http://localhost:8000")
assert '<guid isPermaLink="true">http://localhost:8000/page.html</guid>' in site.route_list['testcollection']._feed._render_content(engine=site.engine, SITE_URL="http://localhost:8000")


@pytest.mark.skip("Invalid Test")
Expand Down
37 changes: 37 additions & 0 deletions tests/test_plugins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import pytest
from src.render_engine.hookspecs import hook_impl
from src.render_engine.page import Page
from src.render_engine.site import Site


class FakePlugin:
"""Clean the output folder before rendering"""

@hook_impl
def pre_build_site(site: type[Site]):
"""Clean the output folder before rendering"""
pass

@pytest.fixture
def site():
class TestSite(Site):
plugins = [
FakePlugin,
]

return TestSite()

def test_register_plugins(site):
"""Check that the plugin is registered"""
assert site._pm.list_name_plugin()[0][0] == 'FakePlugin'


def test_page_plugin_inherits_from_page(site):

class TestPage(Page):
pass


page = Page()
page.register_plugins(*site.plugins)
assert page._pm.list_name_plugin()[0][0] == 'FakePlugin'
16 changes: 8 additions & 8 deletions tests/test_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,23 @@ def test_site_page_in_route_list(tmp_path):
site = Site()

# assert that the route list is empty
assert len(site._route_list) == 0
assert len(site.route_list) == 0

class CustomPage(Page):
test_value = "test"
content_path = file.absolute()

site.page(CustomPage)

assert site._route_list["custompage"].test_value == "test"
assert site.route_list["custompage"].test_value == "test"


def test_site_collection_in_route_list():
"""Tests that when a collection is added to the route_list it is only the colleciton"""
site = Site()

# assert that the route list is empty
assert len(site._route_list) == 0
assert len(site.route_list) == 0

class CustomPage1(Page):
pass
Expand All @@ -81,9 +81,9 @@ class collection(Collection):

collection = site.collection(collection)

assert site._route_list["collection"] == collection
assert len(site._route_list) == 1
assert 'custompage1' in [getattr(page, page._reference) for page in site._route_list["collection"]]
assert site.route_list["collection"] == collection
assert len(site.route_list) == 1
assert 'custompage1' in [getattr(page, page._reference) for page in site.route_list["collection"]]


def test_site_page_with_multiple_routes_has_one_entry_in_routes_list():
Expand All @@ -96,7 +96,7 @@ class CustomPage(Page):

site.page(CustomPage)

assert len(site._route_list) == 1
assert len(site.route_list) == 1

def test_url_for_Page_in_site(tmp_path):
"""Tests that url_for a page is added to a template"""
Expand Down Expand Up @@ -139,7 +139,7 @@ class CustomCollection(Collection):
has_archive = True
pages = [CustomCollectionPage()]

print(site._route_list)
print(site.route_list)

site.render()
print(list(tmp_path.iterdir()))
Expand Down

0 comments on commit 4bc2ea1

Please sign in to comment.