diff --git a/docs/conf.py b/docs/conf.py index f9800022..3e4e6c8c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -83,4 +83,4 @@ intersphinx_mapping.update({ }) -master_doc = "index" \ No newline at end of file +master_doc = "index" diff --git a/moban/constants.py b/moban/constants.py index f113c83a..920c5e54 100644 --- a/moban/constants.py +++ b/moban/constants.py @@ -64,6 +64,7 @@ LABEL_SOURCE = "source" LABEL_DEST = "destination" LABEL_FORCE_TEMPLATE_TYPE = "force_template_type" +LABEL_TEMPLATE_TYPES = "template_types" # error messages ERROR_DATA_FILE_NOT_FOUND = "Both %s and %s does not exist" @@ -98,6 +99,10 @@ PYPI_PACKAGE_NAME = "name" REQUIRE_TYPE = "type" +# Template types +TEMPLATE_TYPES_BASE_TYPE = "base_type" +TEMPLATE_TYPES_OPTIONS = "options" +TEMPLATE_TYPES_FILE_EXTENSIONS = "file_extensions" # Extension JINJA_FILTER_EXTENSION = "jinja_filter" diff --git a/moban/jinja2/engine.py b/moban/jinja2/engine.py index e51af380..0d525f0d 100644 --- a/moban/jinja2/engine.py +++ b/moban/jinja2/engine.py @@ -53,7 +53,7 @@ def __init__(self): constants.TEMPLATE_ENGINE_EXTENSION, tags=["jinja2", "jinja", "jj2", "j2"] ) class Engine(object): - def __init__(self, template_dirs, extensions=None): + def __init__(self, template_dirs, options=None): """ Contruct a jinja2 template engine @@ -73,10 +73,15 @@ def __init__(self, template_dirs, extensions=None): extension for extension in JINJA2_THIRD_PARTY_EXTENSIONS ], # get a copy of this global variable ) - if is_extension_list_valid(extensions): - # because it is modified here - env_params["extensions"] += extensions - import_module_of_extension(extensions) + if options: + if "extensions" in options: + extensions = options.pop("extensions") + if is_extension_list_valid(extensions): + # because it is modified here + env_params["extensions"] += extensions + import_module_of_extension(extensions) + + env_params.update(options) self.jj2_environment = Environment(**env_params) for filter_name, filter_function in FILTERS.get_all(): self.jj2_environment.filters[filter_name] = filter_function diff --git a/moban/mobanfile/__init__.py b/moban/mobanfile/__init__.py index dcab849c..c4a2d3d9 100644 --- a/moban/mobanfile/__init__.py +++ b/moban/mobanfile/__init__.py @@ -62,6 +62,12 @@ def handle_moban_file_v1(moban_file_configurations, command_line_options): if extensions: plugins.ENGINES.register_extensions(extensions) + template_types = moban_file_configurations.get( + constants.LABEL_TEMPLATE_TYPES + ) + if template_types: + plugins.ENGINES.register_options(template_types) + if targets: if target: targets = target diff --git a/moban/plugins/template.py b/moban/plugins/template.py index 3224ae59..0a9f08e1 100644 --- a/moban/plugins/template.py +++ b/moban/plugins/template.py @@ -16,35 +16,52 @@ class MobanFactory(PluginManager): def __init__(self): super(MobanFactory, self).__init__(constants.TEMPLATE_ENGINE_EXTENSION) self.extensions = {} + self.options_registry = {} def register_extensions(self, extensions): self.extensions.update(extensions) + def register_options(self, template_types): + # need the value of 'template_types' + # see test_get_user_defined_engine for help + self.options_registry.update(template_types) + def get_engine(self, template_type, template_dirs, context_dirs): - engine_cls = self.load_me_now(template_type) - engine_extensions = self.extensions.get(template_type) - return MobanEngine( - template_dirs, context_dirs, engine_cls, engine_extensions - ) + if template_type in self.options_registry: + custom_engine_spec = self.options_registry[template_type] + engine_cls = self.load_me_now( + custom_engine_spec[constants.TEMPLATE_TYPES_BASE_TYPE] + ) + options = custom_engine_spec[constants.TEMPLATE_TYPES_OPTIONS] + else: + engine_cls = self.load_me_now(template_type) + engine_extensions = self.extensions.get(template_type) + options = dict(extensions=engine_extensions) + engine = engine_cls(template_dirs, options) + return MobanEngine(template_dirs, context_dirs, engine) + + def get_primary_key(self, template_type): + for key, item in self.options_registry.items(): + if template_type in item[constants.TEMPLATE_TYPES_FILE_EXTENSIONS]: + return key + + return super(MobanFactory, self).get_primary_key(template_type) def all_types(self): - return list(self.registry.keys()) + return list(self.registry.keys()) + list(self.options_registry.keys()) def raise_exception(self, key): raise exceptions.NoThirdPartyEngine(key) class MobanEngine(object): - def __init__( - self, template_dirs, context_dirs, engine_cls, engine_extensions=None - ): + def __init__(self, template_dirs, context_dirs, engine): template_dirs = list(expand_template_directories(template_dirs)) utils.verify_the_existence_of_directories(template_dirs) context_dirs = expand_template_directory(context_dirs) self.context = Context(context_dirs) self.template_dirs = template_dirs - self.engine = engine_cls(self.template_dirs, engine_extensions) - self.engine_cls = engine_cls + self.engine = engine self.templated_count = 0 self.file_count = 0 diff --git a/tests/fixtures/mobanengine/sample_template_type.yml b/tests/fixtures/mobanengine/sample_template_type.yml new file mode 100644 index 00000000..60eeb617 --- /dev/null +++ b/tests/fixtures/mobanengine/sample_template_type.yml @@ -0,0 +1,10 @@ +template_types: + custom_jinja: + base_type: jinja2 # use base_type, instead of overrides + file_extensions: + - moban + - new + - demo_file_suffix + options: + extensions: + - jinja2.ext.do diff --git a/tests/test_engine.py b/tests/test_engine.py index 086851a1..62ed8bb2 100644 --- a/tests/test_engine.py +++ b/tests/test_engine.py @@ -42,7 +42,7 @@ def test_expand_repo_dir(_, __): def test_default_template_type(): engine = ENGINES.get_engine("jj2", [], "") - assert engine.engine_cls == Engine + assert engine.engine.__class__ == Engine class FakeEngine: @@ -53,7 +53,7 @@ def __init__(self, template_dirs, extensions=None): @patch("lml.plugin.PluginManager.load_me_now", return_value=FakeEngine) def test_default_mako_type(_): # fake mako engine = ENGINES.get_engine("fake", [], "") - assert engine.engine_cls.__name__ == "FakeEngine" + assert engine.engine.__class__ == FakeEngine @raises(exceptions.NoThirdPartyEngine) diff --git a/tests/test_jinja2_extensions.py b/tests/test_jinja2_extensions.py index 05e4a2eb..f9009fcb 100644 --- a/tests/test_jinja2_extensions.py +++ b/tests/test_jinja2_extensions.py @@ -12,7 +12,7 @@ def test_globals(): test_dict = dict(hello="world") jinja_global("test", test_dict) path = os.path.join("tests", "fixtures", "globals") - engine = MobanEngine([path], path, Engine) + engine = MobanEngine([path], path, Engine([path])) engine.render_to_file("basic.template", "basic.yml", output) with open(output, "r") as output_file: content = output_file.read() diff --git a/tests/test_template.py b/tests/test_template.py index 360c37a8..d9b9d2b3 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -1,9 +1,12 @@ import os from mock import patch +from nose.tools import eq_ from moban.plugins import ENGINES from moban.definitions import TemplateTarget +from moban.jinja2.engine import Engine +from moban.data_loaders.yaml import open_yaml MODULE = "moban.plugins.template" @@ -80,3 +83,33 @@ def test_do_templates_with_more_shared_data(): content = f.read() assert content == "hello world ox" os.unlink("test") + + +def test_get_user_defined_engine(): + test_fixture = os.path.join( + "tests", "fixtures", "mobanengine", "sample_template_type.yml" + ) + template_types = open_yaml(test_fixture) + ENGINES.register_options(template_types["template_types"]) + engine = ENGINES.get_engine("custom_jinja", ".", ".") + eq_(engine.engine.__class__, Engine) + + +def test_custom_file_extension_is_assocated_with_user_defined_engine(): + test_fixture = os.path.join( + "tests", "fixtures", "mobanengine", "sample_template_type.yml" + ) + template_types = open_yaml(test_fixture) + ENGINES.register_options(template_types["template_types"]) + template_type = ENGINES.get_primary_key("demo_file_suffix") + eq_("custom_jinja", template_type) + + +def test_built_in_jinja2_file_extension_still_works(): + test_fixture = os.path.join( + "tests", "fixtures", "mobanengine", "sample_template_type.yml" + ) + template_types = open_yaml(test_fixture) + ENGINES.register_options(template_types["template_types"]) + template_type = ENGINES.get_primary_key("jj2") + eq_("jinja2", template_type)