36
36
import pathlib
37
37
import sys
38
38
import typing
39
+ from typing import Any , Callable , Dict , Iterable , List , Optional , Set
39
40
import mimetypes
40
41
from collections import defaultdict
41
42
from copy import copy
@@ -373,7 +374,7 @@ class Nikola(object):
373
374
plugin_manager : PluginManager
374
375
_template_system : TemplateSystem
375
376
376
- def __init__ (self , ** config ):
377
+ def __init__ (self , ** config ) -> None :
377
378
"""Initialize proper environment for running tasks."""
378
379
# Register our own path handlers
379
380
self .path_handlers = {
@@ -395,7 +396,7 @@ def __init__(self, **config):
395
396
self .timeline = []
396
397
self .pages = []
397
398
self ._scanned = False
398
- self ._template_system : typing . Optional [TemplateSystem ] = None
399
+ self ._template_system : Optional [TemplateSystem ] = None
399
400
self ._THEMES = None
400
401
self ._MESSAGES = None
401
402
self .filters = {}
@@ -996,13 +997,13 @@ def __init__(self, **config):
996
997
# WebP files have no official MIME type yet, but we need to recognize them (Issue #3671)
997
998
mimetypes .add_type ('image/webp' , '.webp' )
998
999
999
- def _filter_duplicate_plugins (self , plugin_list : typing . Iterable [PluginCandidate ]):
1000
+ def _filter_duplicate_plugins (self , plugin_list : Iterable [PluginCandidate ]):
1000
1001
"""Find repeated plugins and discard the less local copy."""
1001
1002
def plugin_position_in_places (plugin : PluginInfo ):
1002
1003
# plugin here is a tuple:
1003
1004
# (path to the .plugin file, path to plugin module w/o .py, plugin metadata)
1005
+ place : pathlib .Path
1004
1006
for i , place in enumerate (self ._plugin_places ):
1005
- place : pathlib .Path
1006
1007
try :
1007
1008
# Path.is_relative_to backport
1008
1009
plugin .source_dir .relative_to (place )
@@ -1025,7 +1026,7 @@ def plugin_position_in_places(plugin: PluginInfo):
1025
1026
result .append (plugins [- 1 ])
1026
1027
return result
1027
1028
1028
- def init_plugins (self , commands_only = False , load_all = False ):
1029
+ def init_plugins (self , commands_only = False , load_all = False ) -> None :
1029
1030
"""Load plugins as needed."""
1030
1031
extra_plugins_dirs = self .config ['EXTRA_PLUGINS_DIRS' ]
1031
1032
self ._loading_commands_only = commands_only
@@ -1086,9 +1087,9 @@ def init_plugins(self, commands_only=False, load_all=False):
1086
1087
# Search for compiler plugins which we disabled but shouldn't have
1087
1088
self ._activate_plugins_of_category ("PostScanner" )
1088
1089
if not load_all :
1089
- file_extensions = set ()
1090
+ file_extensions : Set [str ] = set ()
1091
+ post_scanner : PostScanner
1090
1092
for post_scanner in [p .plugin_object for p in self .plugin_manager .get_plugins_of_category ('PostScanner' )]:
1091
- post_scanner : PostScanner
1092
1093
exts = post_scanner .supported_extensions ()
1093
1094
if exts is not None :
1094
1095
file_extensions .update (exts )
@@ -1126,8 +1127,8 @@ def init_plugins(self, commands_only=False, load_all=False):
1126
1127
1127
1128
self ._activate_plugins_of_category ("Taxonomy" )
1128
1129
self .taxonomy_plugins = {}
1130
+ taxonomy : Taxonomy
1129
1131
for taxonomy in [p .plugin_object for p in self .plugin_manager .get_plugins_of_category ('Taxonomy' )]:
1130
- taxonomy : Taxonomy
1131
1132
if not taxonomy .is_enabled ():
1132
1133
continue
1133
1134
if taxonomy .classification_name in self .taxonomy_plugins :
@@ -1322,7 +1323,7 @@ def _activate_plugin(self, plugin_info: PluginInfo) -> None:
1322
1323
if candidate .exists () and candidate .is_dir ():
1323
1324
self .template_system .inject_directory (str (candidate ))
1324
1325
1325
- def _activate_plugins_of_category (self , category ) -> typing . List [PluginInfo ]:
1326
+ def _activate_plugins_of_category (self , category ) -> List [PluginInfo ]:
1326
1327
"""Activate all the plugins of a given category and return them."""
1327
1328
# this code duplicated in tests/base.py
1328
1329
plugins = []
@@ -1397,6 +1398,11 @@ def _get_template_system(self):
1397
1398
"plugin\n " .format (template_sys_name ))
1398
1399
sys .exit (1 )
1399
1400
self ._template_system = typing .cast (TemplateSystem , pi .plugin_object )
1401
+
1402
+ engine_factory : Optional [Callable [..., Any ]] = self .config .get ("TEMPLATE_ENGINE_FACTORY" )
1403
+ if engine_factory is not None :
1404
+ self ._template_system .user_engine_factory (engine_factory )
1405
+
1400
1406
lookup_dirs = ['templates' ] + [os .path .join (utils .get_theme_path (name ), "templates" )
1401
1407
for name in self .THEMES ]
1402
1408
self ._template_system .set_directories (lookup_dirs ,
@@ -1444,7 +1450,7 @@ def get_compiler(self, source_name):
1444
1450
1445
1451
return compiler
1446
1452
1447
- def render_template (self , template_name , output_name , context , url_type = None , is_fragment = False ):
1453
+ def render_template (self , template_name : str , output_name : str , context , url_type = None , is_fragment = False ):
1448
1454
"""Render a template with the global context.
1449
1455
1450
1456
If ``output_name`` is None, will return a string and all URL
@@ -1463,7 +1469,7 @@ def render_template(self, template_name, output_name, context, url_type=None, is
1463
1469
utils .TEMPLATES_LOGGER .debug ("For %s, template %s builds %s" , context ["post" ].source_path , template_name , output_name )
1464
1470
else :
1465
1471
utils .TEMPLATES_LOGGER .debug ("Template %s builds %s" , template_name , output_name )
1466
- local_context : typing . Dict [str , typing . Any ] = {}
1472
+ local_context : Dict [str , Any ] = {}
1467
1473
local_context ["template_name" ] = template_name
1468
1474
local_context .update (self .GLOBAL_CONTEXT )
1469
1475
local_context .update (context )
0 commit comments