render-engine 2025.9.1a2__py3-none-any.whl → 2025.10.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- render_engine/page.py +32 -11
- render_engine/render_engine_templates/sitemap.xml +2 -1
- render_engine/render_engine_templates/sitemap_item.xml +2 -2
- render_engine/site.py +12 -3
- render_engine/site_map.py +13 -1
- {render_engine-2025.9.1a2.dist-info → render_engine-2025.10.1.dist-info}/METADATA +1 -1
- {render_engine-2025.9.1a2.dist-info → render_engine-2025.10.1.dist-info}/RECORD +9 -9
- {render_engine-2025.9.1a2.dist-info → render_engine-2025.10.1.dist-info}/WHEEL +0 -0
- {render_engine-2025.9.1a2.dist-info → render_engine-2025.10.1.dist-info}/top_level.txt +0 -0
render_engine/page.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import re
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
from typing import Any
|
|
@@ -10,6 +11,8 @@ from render_engine.themes import ThemeManager
|
|
|
10
11
|
from ._base_object import BaseObject
|
|
11
12
|
from .plugins import PluginManager
|
|
12
13
|
|
|
14
|
+
logger = logging.getLogger("Page")
|
|
15
|
+
|
|
13
16
|
|
|
14
17
|
class BasePage(BaseObject):
|
|
15
18
|
"""
|
|
@@ -28,6 +31,8 @@ class BasePage(BaseObject):
|
|
|
28
31
|
extension (str): The file extension for the page. Defaults to ".html".
|
|
29
32
|
routes (list[str] | Path): The list of routes for the page. Defaults to ["./"].
|
|
30
33
|
template (str | Template | None): The template to use for rendering the page.
|
|
34
|
+
site: The Site object that owns the page.
|
|
35
|
+
no_prerender: Flag to not prerender the content
|
|
31
36
|
"""
|
|
32
37
|
|
|
33
38
|
extension: str = ".html"
|
|
@@ -36,7 +41,8 @@ class BasePage(BaseObject):
|
|
|
36
41
|
rendered_content: str | None
|
|
37
42
|
_reference: str = "_slug"
|
|
38
43
|
plugin_manager: PluginManager | None
|
|
39
|
-
site = None
|
|
44
|
+
site = None # This is a Site but circular imports so we can't actually type hint it.
|
|
45
|
+
no_prerender: bool = False
|
|
40
46
|
|
|
41
47
|
@property
|
|
42
48
|
def _content(self) -> any:
|
|
@@ -69,20 +75,35 @@ class BasePage(BaseObject):
|
|
|
69
75
|
return f"/{route}/{self.path_name}"
|
|
70
76
|
|
|
71
77
|
def _render_from_template(self, template: Template, **kwargs) -> str:
|
|
72
|
-
"""
|
|
78
|
+
"""
|
|
79
|
+
Renders the page from a template.
|
|
80
|
+
|
|
81
|
+
If the content looks like a template that
|
|
82
|
+
|
|
83
|
+
:param template: Template to render
|
|
84
|
+
:param **kwargs: Data to pass into the template for rendering.
|
|
85
|
+
:return: The rendered page
|
|
86
|
+
"""
|
|
73
87
|
template_data = {"data": self._data, "content": self._content}
|
|
74
88
|
if site := getattr(self, "site", None):
|
|
75
89
|
template_data["site_map"] = site.site_map
|
|
76
|
-
if isinstance(self._content, str) and re.search(r"{{
|
|
90
|
+
if not self.no_prerender and isinstance(self._content, str) and re.search(r"{{.*?site_map.*?}}", self._content):
|
|
77
91
|
# If the content looks like a template, try to render it.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
92
|
+
try:
|
|
93
|
+
content_template = Template(self._content)
|
|
94
|
+
except Exception:
|
|
95
|
+
logger.info(f"Failed to parse {repr(self.path_name)} as a template.", exc_info=True)
|
|
96
|
+
else:
|
|
97
|
+
try:
|
|
98
|
+
template_data["content"] = content_template.render(
|
|
99
|
+
**{
|
|
100
|
+
**self.to_dict(),
|
|
101
|
+
**template_data,
|
|
102
|
+
**kwargs,
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
except Exception:
|
|
106
|
+
logger.info(f"Failed to pre-render {repr(self.path_name)}.", exc_info=True)
|
|
86
107
|
|
|
87
108
|
return template.render(
|
|
88
109
|
**{
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<url>
|
|
2
|
-
<loc>{{SITE_URL}}/{{item}}</loc>
|
|
2
|
+
<loc>{{SITE_URL.rstrip("/")}}/{{item.url_for.lstrip("/")}}</loc>
|
|
3
3
|
{% if item.lastmod %}
|
|
4
4
|
<lastmod>{{item.lastmod}}</lastmod>
|
|
5
5
|
{% endif %}
|
|
6
6
|
{% if item.changefreq %}
|
|
7
|
-
<
|
|
7
|
+
<changefreq>{{item.changefreq}}</changefreq>
|
|
8
8
|
{% endif %}
|
|
9
9
|
{% if item.priority %}
|
|
10
10
|
<priority>{{item.priority}}</priority>
|
render_engine/site.py
CHANGED
|
@@ -21,7 +21,8 @@ class Site:
|
|
|
21
21
|
Attributes:
|
|
22
22
|
site_vars (dict): A dictionary containing site-wide variables and their values.
|
|
23
23
|
plugin_settings (dict): A dictionary containing plugin settings.
|
|
24
|
-
|
|
24
|
+
render_html_site_map (bool): Whether to render the generated site map as an HTML page.
|
|
25
|
+
render_xml_site_map (bool): Whether to render the generated site map as XML.
|
|
25
26
|
|
|
26
27
|
Methods:
|
|
27
28
|
update_site_vars(**kwargs): Updates the site-wide variables with the given key-value pairs.
|
|
@@ -51,7 +52,8 @@ class Site:
|
|
|
51
52
|
_template_path: str | Path = "templates"
|
|
52
53
|
_static_paths: set = {"static"}
|
|
53
54
|
plugin_settings: dict = {"plugins": defaultdict(dict)}
|
|
54
|
-
|
|
55
|
+
render_html_site_map: bool = False
|
|
56
|
+
render_xml_site_map: bool = False
|
|
55
57
|
|
|
56
58
|
def __init__(
|
|
57
59
|
self,
|
|
@@ -253,7 +255,7 @@ class Site:
|
|
|
253
255
|
with Progress() as progress:
|
|
254
256
|
task_site_map = progress.add_task("Generating site map", total=1)
|
|
255
257
|
self._site_map = SiteMap(self.route_list, self.site_vars.get("SITE_URL", ""))
|
|
256
|
-
if self.
|
|
258
|
+
if self.render_html_site_map:
|
|
257
259
|
|
|
258
260
|
@self.page
|
|
259
261
|
class SiteMapPage(Page):
|
|
@@ -262,6 +264,13 @@ class Site:
|
|
|
262
264
|
content = self._site_map.html
|
|
263
265
|
template = "page.html"
|
|
264
266
|
|
|
267
|
+
if self.render_xml_site_map:
|
|
268
|
+
|
|
269
|
+
@self.page
|
|
270
|
+
class SiteMapXml(Page):
|
|
271
|
+
path_name = "site_map.xml"
|
|
272
|
+
template = "sitemap.xml"
|
|
273
|
+
|
|
265
274
|
progress.update(task_site_map, advance=1)
|
|
266
275
|
|
|
267
276
|
pre_build_task = progress.add_task("Loading Pre-Build Plugins and Themes", total=1)
|
render_engine/site_map.py
CHANGED
|
@@ -22,7 +22,7 @@ class SiteMapEntry:
|
|
|
22
22
|
self._route = f"/{route.lstrip('/')}/{self.path_name}" if from_collection else f"/{self.path_name}"
|
|
23
23
|
self.entries = list()
|
|
24
24
|
case Collection():
|
|
25
|
-
self._route = f"/{
|
|
25
|
+
self._route = f"/{entry.routes[0].lstrip('/')}"
|
|
26
26
|
self.entries = [
|
|
27
27
|
SiteMapEntry(collection_entry, self._route, from_collection=True) for collection_entry in entry
|
|
28
28
|
]
|
|
@@ -34,6 +34,10 @@ class SiteMapEntry:
|
|
|
34
34
|
"""The URL for the given entry"""
|
|
35
35
|
return str(self._route)
|
|
36
36
|
|
|
37
|
+
def __str__(self) -> str:
|
|
38
|
+
"""String representation of the entry as its URL"""
|
|
39
|
+
return self.url_for
|
|
40
|
+
|
|
37
41
|
|
|
38
42
|
class SiteMap:
|
|
39
43
|
"""Site map"""
|
|
@@ -58,6 +62,12 @@ class SiteMap:
|
|
|
58
62
|
self._collections[sm_entry.slug] = sm_entry
|
|
59
63
|
self.site_url = site_url
|
|
60
64
|
|
|
65
|
+
def __iter__(self):
|
|
66
|
+
"""Iterator for the site map object"""
|
|
67
|
+
for entry in self._route_map.values():
|
|
68
|
+
yield entry
|
|
69
|
+
yield from entry.entries
|
|
70
|
+
|
|
61
71
|
def find(
|
|
62
72
|
self,
|
|
63
73
|
value: str,
|
|
@@ -121,6 +131,8 @@ class SiteMap:
|
|
|
121
131
|
def html(self) -> str:
|
|
122
132
|
"""Build the site map as HTML"""
|
|
123
133
|
html_string = "<ul>\n"
|
|
134
|
+
# We can't iterate over `self` because that will flatten out the site map and we do not want that for the HTML
|
|
135
|
+
# version.
|
|
124
136
|
for entry in self._route_map.values():
|
|
125
137
|
html_string += f'\t<li><a href="{urljoin(self.site_url, entry.url_for)}">{entry.title}</a></li>\n'
|
|
126
138
|
if entry.entries:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: render_engine
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.10.1
|
|
4
4
|
Summary: A Flexible Static Site Generator for Python
|
|
5
5
|
Project-URL: homepage, https://github.com/render-engine/render-engine/
|
|
6
6
|
Project-URL: repository, https://github.com/render-engine/render-engine/
|
|
@@ -9,11 +9,11 @@ render_engine/engine.py,sha256=GOtUiq4ny5GHaLSCeH5u1Zk1JnWJVh63vK7etJiwS20,2843
|
|
|
9
9
|
render_engine/feeds.py,sha256=i-VHsb6pRplMzaenBn6oeqh9yI_N4WVUAExPox6iJgw,921
|
|
10
10
|
render_engine/hookspecs.py,sha256=GhOpw0zTQjfwWOFYYbJ4P7Cvq-oy1MmTPHmd90dr0kg,2292
|
|
11
11
|
render_engine/links.py,sha256=pKmQMTz8-yGX8IecHcrlF3Dkejk7cptaO3qCkQiHB9I,2560
|
|
12
|
-
render_engine/page.py,sha256=
|
|
12
|
+
render_engine/page.py,sha256=l6sKWNJ4gBtC_ONEc0u479q3znL-8Q7U_phNqXqmh6w,8988
|
|
13
13
|
render_engine/plugins.py,sha256=NXM8QTbbRV-DwgpQRoIhILijJBN4SyYg2Rkk1LUAuZM,4703
|
|
14
14
|
render_engine/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
render_engine/site.py,sha256=
|
|
16
|
-
render_engine/site_map.py,sha256=
|
|
15
|
+
render_engine/site.py,sha256=URvG7OQSgeFOcrZwrD8vHLUWa6UxDBxIP-UMeLLqhZM,12936
|
|
16
|
+
render_engine/site_map.py,sha256=I1p_yMDMy1jpIivgNgZptnsxZa8NkcrpciVJE3DlFlQ,5422
|
|
17
17
|
render_engine/themes.py,sha256=TFG1rd34QCBvBWfeDbawgsn6kprmjsDTa1pdDSwDMic,4207
|
|
18
18
|
render_engine/extras/__init__.py,sha256=L4jr4A7Jl-ODnSx1q2fP3_dBo37Dw6yepNRddu1nFNo,72
|
|
19
19
|
render_engine/parsers/markdown.py,sha256=0jpixCaoHaL0IRSvFIljJIRCvFkXoKTEYQNK38LwMDU,287
|
|
@@ -24,15 +24,15 @@ render_engine/render_engine_templates/base_collection_path.md,sha256=7PIn5Oxei-b
|
|
|
24
24
|
render_engine/render_engine_templates/page.html,sha256=p9aZ6_6mouPT1c8FVg-f14MeSt4OB-sH3hcXTY6jGmA,42
|
|
25
25
|
render_engine/render_engine_templates/rss2.0.xml,sha256=Z5LGUdPRr3fQhXtJCjR8uxiPQ_GqYHELleDaS8Tr1oU,1803
|
|
26
26
|
render_engine/render_engine_templates/rss2.0_items.xml,sha256=jxhDG9K2R112-upqq4NZnahDGZcvlWIn_sl9b4ArVEI,1306
|
|
27
|
-
render_engine/render_engine_templates/sitemap.xml,sha256=
|
|
28
|
-
render_engine/render_engine_templates/sitemap_item.xml,sha256=
|
|
27
|
+
render_engine/render_engine_templates/sitemap.xml,sha256=wqtVHwNBLBJrbfScJELHyf2VC3YxjL_cPgnI1xlb67U,184
|
|
28
|
+
render_engine/render_engine_templates/sitemap_item.xml,sha256=8pQ1IHeGO2kDuKhxbQMh8HoDTuaKewtHX2NGt3ztGBY,314
|
|
29
29
|
render_engine/render_engine_templates/base_templates/_archive.html,sha256=eFd62LkMcdxz70g-ksmCmTr2TSnKt2Z2X8zx80JpAPk,189
|
|
30
30
|
render_engine/render_engine_templates/base_templates/_base.html,sha256=piaDrWjE1gG0IvUzpaH1RmHsTeRheeG3S9YmTdIf-CI,710
|
|
31
31
|
render_engine/render_engine_templates/base_templates/_page.html,sha256=jjrY2BAwlJeVSNF4Pa6rd4Kcg0dfYpPpieZE2zeMTOM,163
|
|
32
32
|
render_engine/render_engine_templates/components/footer.html,sha256=HkPGGhfN0HcYm7t8zgXWCQ3bsCbT8FxT4_n2-9e1zUE,74
|
|
33
33
|
render_engine/render_engine_templates/components/page_title.html,sha256=l8aE1TY94UPHXHqAyy6jv4IoN2Hv9cbrTPh7ILkMyxg,137
|
|
34
34
|
render_engine/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
|
-
render_engine-2025.
|
|
36
|
-
render_engine-2025.
|
|
37
|
-
render_engine-2025.
|
|
38
|
-
render_engine-2025.
|
|
35
|
+
render_engine-2025.10.1.dist-info/METADATA,sha256=MMMnXU-jA0JjG9lKbsa-dO5c35Wc4X450rC2_Cstdic,11893
|
|
36
|
+
render_engine-2025.10.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
37
|
+
render_engine-2025.10.1.dist-info/top_level.txt,sha256=aNGALDMsFyrusho04AvUjSivsgEE9tQp_LP_jGr312Q,14
|
|
38
|
+
render_engine-2025.10.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|