Skip to content

Commit 9911221

Browse files
author
Oliver Kandler
committed
new option to merge schema and necessary refactorings
1 parent 3d8e1f5 commit 9911221

5 files changed

Lines changed: 106 additions & 19 deletions

File tree

blurry/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ async def write_html_file(
118118
extra_context["sibling_pages"] = sibling_pages
119119
folder_in_build = convert_content_path_to_directory_in_build(file_data.path)
120120

121-
schema_type = file_data.front_matter.get("@type")
121+
schema_type = file_data.top_level_type
122122
if not schema_type:
123123
raise ValueError(
124124
f"Required @type value missing in file or TOML front matter invalid: "
@@ -207,9 +207,10 @@ async def build(release=True):
207207
file_data_by_directory[directory] = []
208208

209209
# Convert Markdown file to HTML
210-
body, front_matter = convert_markdown_file_to_html(filepath)
210+
body, front_matter, top_level_type = convert_markdown_file_to_html(filepath)
211211
file_data = MarkdownFileData(
212212
body=body,
213+
top_level_type=top_level_type,
213214
front_matter=front_matter,
214215
path=relative_filepath,
215216
)

blurry/markdown/__init__.py

Lines changed: 94 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
from typing import TypeAlias
55
from typing import TypeGuard
66

7+
import json
8+
from pyld import jsonld
9+
710
import mistune
811
from mistune import BlockState
912
from mistune.plugins.abbr import abbr
@@ -149,9 +152,96 @@ def is_blurry_renderer(
149152
+ [plugin.load() for plugin in discovered_markdown_plugins],
150153
)
151154

155+
SCHEMA_ORG = json.loads('{ "@vocab": "https://schema.org/" }')
156+
def jsonld_document_loader(secure=False, fragments=[], **kwargs):
157+
"""
158+
Create a Requests document loader.
159+
160+
Can be used to setup extra Requests args such as verify, cert, timeout,
161+
or others.
162+
163+
:param secure: require all requests to use HTTPS (default: False).
164+
:param fragments: the fragments of schema loaded as dicts
165+
:param **kwargs: extra keyword args for Requests get() call.
166+
167+
:return: the RemoteDocument loader function.
168+
"""
169+
from pyld.jsonld import JsonLdError
170+
171+
def loader(ignored, options={}):
172+
"""
173+
Retrieves JSON-LD from the dicts provided as fragments.
174+
175+
:param ignored: this positional paramter is ignored, because the tomls fragments are side loaded
176+
177+
:return: the RemoteDocument.
178+
"""
179+
fragments_str = []
180+
for fragment in fragments:
181+
if not fragment.get('@context'):
182+
fragment['@context'] = SCHEMA_ORG
183+
fragments_str.append(json.dumps(fragment))
184+
# print("==========================")
185+
# print(json.dumps(fragment, indent=2))
186+
187+
result = '[' + ','.join(fragments_str) + ']'
188+
# print(">>>>>>>>> ",result)
189+
190+
doc = {
191+
'contentType': 'application/ld+json',
192+
'contextUrl': None,
193+
'documentUrl': None,
194+
'document': result
195+
}
196+
return doc
152197

153-
def convert_markdown_file_to_html(filepath: Path) -> tuple[str, dict[str, Any]]:
198+
return loader
199+
200+
def add_inferred_schema(local_front_matter: dict, filepath: Path) -> dict:
154201
CONTENT_DIR = get_content_directory()
202+
203+
# Add inferred/computed/relative values
204+
local_front_matter.update({"url": content_path_to_url(filepath.relative_to(CONTENT_DIR))})
205+
206+
# Add inferred/computed/relative values
207+
# https://schema.org/image
208+
# https://schema.org/thumbnailUrl
209+
if image := front_matter.get("image"):
210+
image_copy = deepcopy(image)
211+
relative_image_path = get_relative_image_path_from_image_property(image_copy)
212+
image_path = resolve_relative_path_in_markdown(relative_image_path, filepath)
213+
front_matter["image"] = update_image_with_url(image_copy, image_path)
214+
front_matter["thumbnailUrl"] = image_path_to_thumbnailUrl(image_path)
215+
216+
return local_front_matter
217+
218+
def resolve_front_matter(state: dict, filepath: Path) -> tuple[dict[str, Any], str]:
219+
if SETTINGS.get("FRONT_MATTER_RESOLUTION") == "merge":
220+
try:
221+
global_schema = dict(SETTINGS.get("SCHEMA_DATA", {}))
222+
if not global_schema.get('@context'):
223+
global_schema['@context'] = SCHEMA_ORG
224+
225+
local_schema = state.env.get("front_matter", {})
226+
top_level_type = local_schema.get("@type", None)
227+
if not local_schema.get('@context'):
228+
local_schema['@context'] = SCHEMA_ORG
229+
local_schema = add_inferred_schema(local_schema, filepath)
230+
jsonld.set_document_loader(jsonld_document_loader(fragments=[global_schema, local_schema]))
231+
front_matter: dict[str, Any] = jsonld.compact("ignore", SCHEMA_ORG)
232+
except Exception as e:
233+
print("merging front matter failed:", e)
234+
raise e
235+
else:
236+
# Seed front_matter with schema_data from config file
237+
front_matter: dict[str, Any] = dict(SETTINGS.get("SCHEMA_DATA", {}))
238+
front_matter.update(state.env.get("front_matter", {}))
239+
front_matter = add_inferred_schema(front_matter, filepath)
240+
241+
top_level_type = None
242+
return front_matter, top_level_type
243+
244+
def convert_markdown_file_to_html(filepath: Path) -> tuple[str, dict[str, Any], str]:
155245
if not markdown.renderer:
156246
raise Exception("Blurry markdown renderer not set on Mistune Markdown instance")
157247

@@ -167,26 +257,13 @@ def convert_markdown_file_to_html(filepath: Path) -> tuple[str, dict[str, Any]]:
167257
html, state = markdown.parse(markdown_text, state=state)
168258

169259
if not is_str(html):
170-
raise Exception(f"Expected html to be a string but got: {type(html)}")
260+
raise Exception(f"Expected html to be a string but got: {top_level_type(html)}")
171261

172262
# Post-process HTML
173263
html = remove_lazy_loading_from_first_image(html)
174264

175-
# Seed front_matter with schema_data from config file
176-
front_matter: dict[str, Any] = dict(SETTINGS.get("SCHEMA_DATA", {}))
177-
front_matter.update(state.env.get("front_matter", {}))
178-
179-
# Add inferred/computed/relative values
180-
# https://schema.org/image
181-
# https://schema.org/thumbnailUrl
182-
front_matter.update({"url": content_path_to_url(filepath.relative_to(CONTENT_DIR))})
183-
if image := front_matter.get("image"):
184-
image_copy = deepcopy(image)
185-
relative_image_path = get_relative_image_path_from_image_property(image_copy)
186-
image_path = resolve_relative_path_in_markdown(relative_image_path, filepath)
187-
front_matter["image"] = update_image_with_url(image_copy, image_path)
188-
front_matter["thumbnailUrl"] = image_path_to_thumbnailUrl(image_path)
189-
return html, front_matter
265+
front_matter, top_level_type = resolve_front_matter(state, filepath)
266+
return html, front_matter, top_level_type
190267

191268

192269
def image_path_to_thumbnailUrl(image_path: Path):

blurry/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
@dataclass
99
class MarkdownFileData:
1010
body: str
11+
top_level_type: str
1112
front_matter: dict[str, Any]
1213
path: Path
1314

tests/test_sitemap.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,19 @@
88
directory_file_data = [
99
MarkdownFileData(
1010
front_matter=dict(datePublished=date(2021, 1, 1), url="/blog/a-post-1/"),
11+
top_level_type = "WebPage",
1112
body="",
1213
path=blog_path / "a-post-1",
1314
),
1415
MarkdownFileData(
1516
front_matter=dict(datePublished=date(2021, 3, 1), url="/blog/b-post-3/"),
17+
top_level_type = "WebPage",
1618
body="",
1719
path=blog_path / "b-post-3",
1820
),
1921
MarkdownFileData(
2022
front_matter=dict(dateCreated=date(2021, 2, 1), url="/blog/c-post-2/"),
23+
top_level_type = "WebPage",
2124
body="",
2225
path=blog_path / "c-post-2",
2326
),
@@ -27,6 +30,7 @@
2730
dateModified=date(2022, 1, 13),
2831
url="/blog/c-post-4/",
2932
),
33+
top_level_type = "WebPage",
3034
body="",
3135
path=blog_path / "c-post-4",
3236
),

tests/test_utils.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,21 +67,25 @@ def test_sort_directory_file_data_by_date():
6767
blog_path: [
6868
MarkdownFileData(
6969
front_matter=dict(datePublished=date(2021, 1, 1)),
70+
top_level_type = "WebPage",
7071
body="",
7172
path=Path("a-post-1"),
7273
),
7374
MarkdownFileData(
7475
front_matter=dict(datePublished=date(2021, 3, 1)),
76+
top_level_type = "WebPage",
7577
body="",
7678
path=Path("b-post-3"),
7779
),
7880
MarkdownFileData(
7981
front_matter=dict(dateCreated=date(2021, 2, 1)),
82+
top_level_type = "WebPage",
8083
body="",
8184
path=Path("c-post-2"),
8285
),
8386
MarkdownFileData(
8487
front_matter=dict(),
88+
top_level_type = "WebPage",
8589
body="",
8690
path=Path("c-post-4"),
8791
),

0 commit comments

Comments
 (0)