blurry-cli 0.11.0__tar.gz → 0.13.0__tar.gz

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.
Files changed (31) hide show
  1. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/PKG-INFO +1 -1
  2. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/__init__.py +165 -67
  3. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/images.py +29 -21
  4. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/markdown/__init__.py +2 -2
  5. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/plugins/jinja_plugins/blurry_image_extension.py +1 -1
  6. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/sitemap.py +1 -3
  7. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/templates.py +6 -5
  8. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/pyproject.toml +1 -1
  9. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/LICENSE +0 -0
  10. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/README.md +0 -0
  11. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/__main__.py +0 -0
  12. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/async_typer.py +0 -0
  13. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/cli.py +0 -0
  14. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/constants.py +0 -0
  15. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/markdown/front_matter.py +0 -0
  16. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/markdown/renderer_functions/__init__.py +0 -0
  17. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/markdown/renderer_functions/render_video.py +0 -0
  18. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/open_graph.py +0 -0
  19. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/plugins/__init__.py +0 -0
  20. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/plugins/html_plugins/__init__.py +0 -0
  21. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/plugins/html_plugins/minify_html_plugin.py +0 -0
  22. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/plugins/jinja_plugins/__init__.py +0 -0
  23. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/plugins/markdown_plugins/__init__.py +0 -0
  24. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/plugins/markdown_plugins/container_plugin.py +0 -0
  25. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/plugins/markdown_plugins/punctuation_plugin.py +0 -0
  26. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/plugins/markdown_plugins/python_code_plugin.py +0 -0
  27. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/py.typed +0 -0
  28. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/schema_validation.py +0 -0
  29. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/settings.py +0 -0
  30. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/types.py +0 -0
  31. {blurry_cli-0.11.0 → blurry_cli-0.13.0}/blurry/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: blurry-cli
3
- Version: 0.11.0
3
+ Version: 0.13.0
4
4
  Summary: A Mistune-based static site generator for Python
5
5
  Home-page: https://github.com/blurry-dev/blurry
6
6
  License: MIT
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import concurrent.futures
2
3
  import dataclasses
3
4
  import importlib
4
5
  import json
@@ -7,7 +8,6 @@ import os
7
8
  import pkgutil
8
9
  import shutil
9
10
  import sys
10
- from collections.abc import Coroutine
11
11
  from copy import deepcopy
12
12
  from datetime import datetime
13
13
  from pathlib import Path
@@ -17,6 +17,10 @@ from jinja2 import Environment
17
17
  from livereload import Server
18
18
  from rich import print
19
19
  from rich.console import Console
20
+ from rich.progress import BarColumn
21
+ from rich.progress import Progress
22
+ from rich.progress import TaskProgressColumn
23
+ from rich.progress import TextColumn
20
24
 
21
25
  from blurry.async_typer import AsyncTyper
22
26
  from blurry.cli import print_blurry_name
@@ -54,51 +58,83 @@ warning_console = Console(stderr=True, style="bold yellow")
54
58
  app = AsyncTyper()
55
59
 
56
60
 
57
- async def process_non_markdown_file(filepath: Path):
61
+ def process_non_markdown_file(
62
+ filepath: Path, file_data_by_directory, jinja_env: Environment
63
+ ):
64
+ # Process Jinja files
65
+ if ".jinja" in filepath.suffixes:
66
+ # Process file
67
+ process_jinja_file(filepath, jinja_env, file_data_by_directory)
68
+ return
69
+
58
70
  CONTENT_DIR = get_content_directory()
59
71
  mimetype, _ = mimetypes.guess_type(filepath, strict=False)
60
72
  relative_filepath = filepath.relative_to(CONTENT_DIR)
61
- build_filepath = get_build_directory() / relative_filepath
62
- output_file = Path(build_filepath)
63
- output_file.parent.mkdir(exist_ok=True, parents=True)
73
+ output_file = get_build_directory() / relative_filepath
64
74
 
65
- # Copy file to build directory
66
- shutil.copyfile(filepath, build_filepath)
75
+ # Copy file to build directory if it is not already there
76
+ if not output_file.exists():
77
+ output_file.parent.mkdir(exist_ok=True, parents=True)
78
+ shutil.copyfile(filepath, output_file)
67
79
 
68
80
  # Create srcset images
69
81
  if mimetype in [
70
82
  mimetypes.types_map[".jpg"],
71
83
  mimetypes.types_map[".png"],
72
84
  ]:
73
- await generate_images_for_srcset(filepath)
85
+ asyncio.run(generate_images_for_srcset(filepath))
74
86
 
75
87
 
76
- async def write_html_file(
77
- file_data: MarkdownFileData,
78
- file_data_list: list[MarkdownFileData],
88
+ def process_jinja_file(filepath: Path, jinja_env: Environment, file_data_by_directory):
89
+ build_directory = get_build_directory()
90
+ content_directory = get_content_directory()
91
+ template = jinja_env.get_template(str(filepath.relative_to(content_directory)))
92
+ context = {
93
+ "file_data_by_directory": {
94
+ str(path): data for path, data in deepcopy(file_data_by_directory).items()
95
+ },
96
+ "settings": deepcopy(SETTINGS),
97
+ "datetime": datetime,
98
+ }
99
+ filepath_with_new_extension = filepath.with_suffix(
100
+ filepath.suffix.replace(".jinja", "")
101
+ )
102
+ filepath_in_build = build_directory / filepath_with_new_extension.relative_to(
103
+ content_directory
104
+ )
105
+ html = template.render(dataclasses=dataclasses, **context)
106
+ filepath_in_build.write_text(html)
107
+
108
+
109
+ def write_html_file(
110
+ filepath: Path,
79
111
  file_data_by_directory: dict[Path, list[MarkdownFileData]],
80
112
  release: bool,
81
113
  jinja_env: Environment,
82
114
  ):
83
115
  extra_context: TemplateContext = {}
84
116
  # Gather data from other files in this directory if this is an index file
85
- if file_data.path.name == "index.md":
117
+ file_data_list = file_data_by_directory[filepath.parent]
118
+ if filepath.name == "index.md":
86
119
  sibling_pages = [
87
120
  {
88
121
  "url": content_path_to_url(f.path),
89
122
  **f.front_matter,
90
123
  }
91
124
  for f in file_data_list
92
- if f.path != file_data.path
125
+ if f.path != filepath
93
126
  ]
94
127
  extra_context["sibling_pages"] = sibling_pages
95
- folder_in_build = convert_content_path_to_directory_in_build(file_data.path)
128
+ folder_in_build = convert_content_path_to_directory_in_build(filepath)
96
129
 
130
+ file_data = [
131
+ f for f in file_data_by_directory[filepath.parent] if f.path == filepath
132
+ ][0]
97
133
  schema_type = file_data.front_matter.get("@type")
98
134
  if not schema_type:
99
135
  raise ValueError(
100
136
  f"Required @type value missing in file or TOML front matter invalid: "
101
- f"{file_data.path}"
137
+ f"{filepath}"
102
138
  )
103
139
  template_extension = SETTINGS["MARKDOWN_FILE_JINJA_TEMPLATE_EXTENSION"]
104
140
  template = jinja_env.get_template(f"{schema_type}{template_extension}")
@@ -124,12 +160,13 @@ async def write_html_file(
124
160
  default=json_converter_with_dates,
125
161
  )
126
162
 
127
- validate_front_matter_as_schema(file_data.path, front_matter, warning_console)
163
+ validate_front_matter_as_schema(filepath, front_matter, warning_console)
128
164
 
129
165
  schema_type_tag = f'<script type="application/ld+json">{schema_data}</script>'
130
166
 
131
167
  template_context = {
132
168
  "body": file_data.body,
169
+ "filepath": filepath,
133
170
  "schema_data": schema_data,
134
171
  "schema_type_tag": schema_type_tag,
135
172
  "open_graph_tags": open_graph_meta_tags(file_data.front_matter),
@@ -154,40 +191,15 @@ async def write_html_file(
154
191
  write_index_file_creating_path(folder_in_build, html)
155
192
 
156
193
 
157
- @app.async_command()
158
- async def build(release=True):
159
- """Generates HTML content from Markdown files."""
160
-
161
- print_blurry_name()
162
- print_plugin_table()
163
-
164
- update_settings()
165
- jinja_env = get_jinja_env()
166
- os.environ.setdefault(f"{ENV_VAR_PREFIX}BUILD_MODE", "prod" if release else "dev")
167
- CONTENT_DIR = get_content_directory()
168
- BUILD_DIR = get_build_directory()
169
- start = datetime.now()
170
- path = Path(CONTENT_DIR)
194
+ def gather_file_data_by_directory() -> DirectoryFileData:
195
+ # Sort file data by publishedDate/createdDate, descending, if present
171
196
  file_data_by_directory: DirectoryFileData = {}
172
- if not BUILD_DIR.exists():
173
- BUILD_DIR.mkdir(parents=True)
174
-
175
- markdown_tasks: list[Coroutine] = []
176
- non_markdown_tasks: list[Coroutine] = []
177
-
178
- for filepath in path.glob("**/*.*"):
179
- # Handle images and other files
180
- if filepath.suffix != ".md":
181
- non_markdown_tasks.append(process_non_markdown_file(filepath))
182
- continue
183
-
184
- # Handle Markdown files
197
+ content_directory = get_content_directory()
185
198
 
199
+ for filepath in content_directory.glob("**/*.md"):
186
200
  # Extract filepath for storing context data and writing out
187
- relative_filepath = filepath.relative_to(CONTENT_DIR)
201
+ relative_filepath = filepath.relative_to(content_directory)
188
202
  directory = relative_filepath.parent
189
- if directory not in file_data_by_directory:
190
- file_data_by_directory[directory] = []
191
203
 
192
204
  # Convert Markdown file to HTML
193
205
  body, front_matter = convert_markdown_file_to_html(filepath)
@@ -196,33 +208,79 @@ async def build(release=True):
196
208
  front_matter=front_matter,
197
209
  path=relative_filepath,
198
210
  )
199
- file_data_by_directory[directory].append(file_data)
211
+ try:
212
+ file_data_by_directory[directory].append(file_data)
213
+ except KeyError:
214
+ file_data_by_directory[directory] = [file_data]
200
215
 
201
- non_markdown_tasks.append(write_sitemap_file(file_data_by_directory))
216
+ return sort_directory_file_data_by_date(file_data_by_directory)
202
217
 
203
- # Sort file data by publishedDate/createdDate, descending, if present
204
- file_data_by_directory = sort_directory_file_data_by_date(file_data_by_directory)
205
-
206
- for file_data_list in file_data_by_directory.values():
207
- for file_data in file_data_list:
208
- markdown_tasks.append(
209
- write_html_file(
210
- file_data,
211
- file_data_list,
218
+
219
+ @app.async_command()
220
+ async def build(release=True):
221
+ """Generates HTML content from Markdown files."""
222
+ start = datetime.now()
223
+
224
+ if release:
225
+ print_blurry_name()
226
+ print_plugin_table()
227
+
228
+ update_settings()
229
+ content_directory = get_content_directory()
230
+ build_directory = get_build_directory()
231
+ build_directory.mkdir(parents=True, exist_ok=True)
232
+ jinja_env = get_jinja_env()
233
+
234
+ os.environ.setdefault(f"{ENV_VAR_PREFIX}BUILD_MODE", "prod" if release else "dev")
235
+
236
+ file_data_by_directory = gather_file_data_by_directory()
237
+
238
+ markdown_task_count = 0
239
+ non_markdown_task_count = 1 # sitemap
240
+
241
+ with Progress(
242
+ TextColumn("[progress.description]{task.description}"),
243
+ BarColumn(),
244
+ TaskProgressColumn(),
245
+ transient=True,
246
+ ) as progress:
247
+ with concurrent.futures.ThreadPoolExecutor() as executor:
248
+ markdown_task = progress.add_task("[blue]Markdown")
249
+ other_task = progress.add_task("[blue]Other")
250
+
251
+ sitemap_future = executor.submit(write_sitemap_file, file_data_by_directory)
252
+ sitemap_future.add_done_callback(lambda _: progress.advance(other_task))
253
+
254
+ for filepath in content_directory.rglob("*"):
255
+ if filepath.is_dir():
256
+ continue
257
+ if filepath.suffix == ".md":
258
+ markdown_future = executor.submit(
259
+ write_html_file,
260
+ filepath.relative_to(content_directory),
261
+ file_data_by_directory,
262
+ release,
263
+ jinja_env,
264
+ )
265
+ markdown_task_count += 1
266
+ progress.update(markdown_task, total=markdown_task_count)
267
+ markdown_future.add_done_callback(
268
+ lambda _: progress.advance(markdown_task)
269
+ )
270
+ continue
271
+ other_future = executor.submit(
272
+ process_non_markdown_file,
273
+ filepath,
212
274
  file_data_by_directory,
213
- release,
214
275
  jinja_env,
215
276
  )
216
- )
217
-
218
- content_dir_relative = CONTENT_DIR.relative_to(Path.cwd())
219
- print(f"Blurring {len(markdown_tasks)} Markdown files from: {content_dir_relative}")
277
+ non_markdown_task_count += 1
278
+ progress.update(other_task, total=non_markdown_task_count)
279
+ other_future.add_done_callback(lambda _: progress.advance(other_task))
220
280
 
221
- await asyncio.gather(*markdown_tasks)
222
- loop = asyncio.new_event_loop()
223
- asyncio.set_event_loop(loop)
224
- for non_markdown_task in non_markdown_tasks:
225
- await asyncio.to_thread(lambda: loop.run_until_complete(non_markdown_task))
281
+ print(
282
+ f"Blurring {markdown_task_count} Markdown files and {non_markdown_task_count} other files"
283
+ )
226
284
 
227
285
  end = datetime.now()
228
286
 
@@ -251,6 +309,9 @@ async def reload_local_plugins_and_build():
251
309
  @app.command()
252
310
  def runserver():
253
311
  """Starts HTTP server with live reloading."""
312
+ print_blurry_name()
313
+ print_plugin_table()
314
+
254
315
  update_settings()
255
316
  os.environ.setdefault(f"{ENV_VAR_PREFIX}BUILD_MODE", "dev")
256
317
 
@@ -259,14 +320,51 @@ def runserver():
259
320
  event_loop = asyncio.get_event_loop()
260
321
  event_loop.create_task(build_development())
261
322
 
323
+ jinja_env = get_jinja_env()
324
+
325
+ def handle_changed_jinja_files(filepaths: list[str]):
326
+ file_data_by_directory = gather_file_data_by_directory()
327
+ for filepath in filepaths:
328
+ process_jinja_file(
329
+ Path.cwd() / filepath,
330
+ jinja_env,
331
+ file_data_by_directory,
332
+ )
333
+
334
+ def handle_changed_markdown_files(filepaths: list[str]):
335
+ file_data_by_directory = gather_file_data_by_directory()
336
+ content_directory = get_content_directory()
337
+ for filepath in filepaths:
338
+ write_html_file(
339
+ filepath=(Path.cwd() / filepath).relative_to(content_directory),
340
+ file_data_by_directory=file_data_by_directory,
341
+ release=False,
342
+ jinja_env=jinja_env,
343
+ )
344
+
262
345
  livereload_server = Server()
346
+ livereload_server.watch(
347
+ f"{SETTINGS['CONTENT_DIRECTORY_NAME']}/**/*.jinja", handle_changed_jinja_files
348
+ )
349
+ livereload_server.watch(
350
+ f"{SETTINGS['CONTENT_DIRECTORY_NAME']}/**/*.md",
351
+ handle_changed_markdown_files,
352
+ )
263
353
  livereload_server.watch(
264
354
  f"{SETTINGS['CONTENT_DIRECTORY_NAME']}/**/*",
265
355
  lambda: event_loop.create_task(build_development()),
356
+ ignore=lambda filepath: any(
357
+ [
358
+ filepath.endswith(".md"),
359
+ filepath.endswith(".jinja"),
360
+ Path(filepath).is_dir(),
361
+ ]
362
+ ),
266
363
  )
267
364
  livereload_server.watch(
268
365
  f"{SETTINGS['TEMPLATES_DIRECTORY_NAME']}/**/*",
269
366
  lambda: event_loop.create_task(build_development()),
367
+ ignore=lambda filepath: Path(filepath).is_dir(),
270
368
  )
271
369
  livereload_server.watch(
272
370
  "./**/*.py",
@@ -1,4 +1,4 @@
1
- import asyncio
1
+ import concurrent.futures
2
2
  from pathlib import Path
3
3
 
4
4
  from wand.image import Image
@@ -30,7 +30,7 @@ def add_image_width_to_path(image_path: Path, width: int) -> Path:
30
30
  return Path(new_filename)
31
31
 
32
32
 
33
- async def convert_image_to_avif(image_path: Path, target_path: Path | None = None):
33
+ def convert_image_to_avif(image_path: Path, target_path: Path | None = None):
34
34
  AVIF_COMPRESSION_QUALITY = SETTINGS["AVIF_COMPRESSION_QUALITY"]
35
35
  image_suffix = image_path.suffix
36
36
  avif_filepath = str(target_path or image_path).replace(image_suffix, ".avif")
@@ -42,31 +42,39 @@ async def convert_image_to_avif(image_path: Path, target_path: Path | None = Non
42
42
  image.save(filename=avif_filepath)
43
43
 
44
44
 
45
+ def clone_and_resize_image(
46
+ image: Image, target_width: int, resized_image_destination: Path
47
+ ):
48
+ if resized_image_destination.exists():
49
+ return
50
+ image.transform(resize=str(target_width))
51
+ image.save(filename=resized_image_destination)
52
+
53
+
45
54
  async def generate_images_for_srcset(image_path: Path):
46
55
  BUILD_DIR = get_build_directory()
47
56
  CONTENT_DIR = get_content_directory()
57
+ filepaths_to_convert_to_avif = []
58
+
59
+ build_path = BUILD_DIR / image_path.resolve().relative_to(CONTENT_DIR)
60
+ with concurrent.futures.ThreadPoolExecutor() as executor:
61
+ with Image(filename=str(image_path)) as img:
62
+ width = img.width
63
+
64
+ for target_width in get_widths_for_image_width(width):
65
+ new_filepath = add_image_width_to_path(image_path, target_width)
66
+ relative_filepath = new_filepath.resolve().relative_to(CONTENT_DIR)
67
+ build_filepath = BUILD_DIR / relative_filepath
68
+ # We convert the resized images to AVIF, so do this synchronously
69
+ clone_and_resize_image(img, target_width, build_filepath)
70
+ filepaths_to_convert_to_avif.append(build_filepath)
48
71
 
49
- with Image(filename=str(image_path)) as img:
50
- width = img.width
51
72
  # Convert original image
52
- build_path = BUILD_DIR / image_path.resolve().relative_to(CONTENT_DIR)
53
- await convert_image_to_avif(image_path=image_path, target_path=build_path)
54
-
55
- avif_files_to_create: list[Path] = []
56
- for target_width in get_widths_for_image_width(width):
57
- new_filepath = add_image_width_to_path(image_path, target_width)
58
- relative_filepath = new_filepath.resolve().relative_to(CONTENT_DIR)
59
- build_filepath = BUILD_DIR / relative_filepath
60
- with img.clone() as resized:
61
- avif_files_to_create.append(build_filepath)
62
- if build_filepath.exists():
63
- continue
64
- resized.transform(resize=str(target_width))
65
- resized.save(filename=build_filepath)
66
-
67
- await asyncio.gather(
68
- *[convert_image_to_avif(avif_file) for avif_file in avif_files_to_create]
73
+ executor.submit(
74
+ convert_image_to_avif, image_path=image_path, target_path=build_path
69
75
  )
76
+ # Generate AVIF files for resized images
77
+ executor.map(convert_image_to_avif, filepaths_to_convert_to_avif)
70
78
 
71
79
 
72
80
  def get_widths_for_image_width(image_width: int) -> list[int]:
@@ -84,7 +84,7 @@ class BlurryRenderer(mistune.HTMLRenderer):
84
84
  attributes_str = " ".join(
85
85
  f'{name}="{value}"' for name, value in attributes.items()
86
86
  )
87
- return f"<img {attributes_str} >"
87
+ return f"<img {attributes_str}>"
88
88
 
89
89
  image_widths = get_widths_for_image_width(image_width)
90
90
 
@@ -103,7 +103,7 @@ class BlurryRenderer(mistune.HTMLRenderer):
103
103
 
104
104
  return (
105
105
  f"<figure>"
106
- f"<picture>{source_tag}<img {attributes_str} /></picture>"
106
+ f"<picture>{source_tag}<img {attributes_str}></picture>"
107
107
  f'<figcaption>{attributes["alt"]}</figcaption>'
108
108
  f"</figure>"
109
109
  )
@@ -73,4 +73,4 @@ class BlurryImage(StandaloneTag):
73
73
  f'{name}="{value}"' for name, value in attributes.items()
74
74
  )
75
75
 
76
- return f"<img {attributes_str}/>"
76
+ return f"<img {attributes_str}>"
@@ -38,9 +38,7 @@ def generate_sitemap_for_file_data_list(file_data_list: list[MarkdownFileData])
38
38
  return SITEMAP_TEMPLATE.format(urls=sitemap_url_content)
39
39
 
40
40
 
41
- async def write_sitemap_file(
42
- file_data_by_directory: dict[Path, list[MarkdownFileData]]
43
- ):
41
+ def write_sitemap_file(file_data_by_directory: dict[Path, list[MarkdownFileData]]):
44
42
  BUILD_DIR = get_build_directory()
45
43
  file_data = []
46
44
  for file_data_list in file_data_by_directory.values():
@@ -5,6 +5,7 @@ from jinja2 import select_autoescape
5
5
 
6
6
  from blurry.plugins import discovered_jinja_extensions
7
7
  from blurry.plugins import discovered_jinja_filter_plugins
8
+ from blurry.settings import get_content_directory
8
9
  from blurry.settings import get_templates_directory
9
10
  from blurry.settings import SETTINGS
10
11
 
@@ -14,16 +15,16 @@ def get_jinja_env() -> Environment:
14
15
  Returns a Jinja environment complete with JinjaX and any installed Jinja extensions and filters.
15
16
  """
16
17
  templates_directory = get_templates_directory()
18
+ content_directory = get_content_directory()
17
19
  jinja_env = Environment(
18
- loader=FileSystemLoader(templates_directory),
20
+ loader=FileSystemLoader([content_directory, templates_directory]),
19
21
  autoescape=select_autoescape(
20
- list(
22
+ enabled_extensions=list(
21
23
  {
22
24
  SETTINGS["MARKDOWN_FILE_JINJA_TEMPLATE_EXTENSION"].lstrip("."),
23
- "html",
24
- "xml",
25
+ "jinja",
25
26
  }
26
- )
27
+ ),
27
28
  ),
28
29
  extensions=[
29
30
  jinja_extension.load() for jinja_extension in discovered_jinja_extensions
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "blurry-cli"
3
- version = "0.11.0"
3
+ version = "0.13.0"
4
4
  description = "A Mistune-based static site generator for Python"
5
5
  authors = ["John Franey <franey@duck.com>"]
6
6
  license = "MIT"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes