Skip to content

Commit

Permalink
Adding --mustache-remover-env
Browse files Browse the repository at this point in the history
  • Loading branch information
Cimon Lucas (LCM) authored and Cimon Lucas (LCM) committed Aug 13, 2017
1 parent 54848e5 commit b19f083
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 36 deletions.
84 changes: 52 additions & 32 deletions pre_commit_hooks/validate_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def main(argv=None):
help='run on larger files: sets Java stack size to 32768k')
parser.add_argument('--remove-mustaches', action='store_true', default=False)
parser.add_argument('--mustache-remover', choices=('pybar', 'jinja2'), default='pybar')
parser.add_argument('--mustache-remover-env', action='append', nargs=2, help='Predefined KEY VALUE pair to substitute in the template')
parser.add_argument('--mustache-remover-copy-ext', default='~~')
parser.add_argument('--mustache-remover-default-value', default='DUMMY')
parser.add_argument('--templates-include-dir', help='Required for Jinja2 templates that use the `include` directive'
Expand All @@ -40,9 +41,10 @@ def main(argv=None):

logging.basicConfig(level=getattr(logging, args.log))

placeholder = Placeholder(args.mustache_remover_default_value, args.mustache_remover_env)
validator = CustomHTMLValidator(mustache_remover_name=args.mustache_remover,
mustache_remover_copy_ext=args.mustache_remover_copy_ext,
mustache_remover_default_value=args.mustache_remover_default_value,
mustache_remover_placeholder=placeholder,
templates_include_dir=args.templates_include_dir,
directory=None, match=None, ignore=args.ignore, ignore_re=args.ignore_re)
return validator.validate(
Expand All @@ -53,12 +55,19 @@ def main(argv=None):
)


class Placeholder:
def __init__(self, default_value, env=None):
self.default_value = default_value
self.env = {k: eval(v) for k, v in env or ()}



class CustomHTMLValidator(Validator):

def __init__(self, mustache_remover_name, mustache_remover_copy_ext, mustache_remover_default_value, templates_include_dir, *args, **kwargs):
def __init__(self, mustache_remover_name, mustache_remover_copy_ext, mustache_remover_placeholder, templates_include_dir, *args, **kwargs):
Validator.__init__(self, *args, **kwargs)
self.mustache_remover_copy_ext = mustache_remover_copy_ext
self.mustache_remover_default_value = mustache_remover_default_value
self.mustache_remover_placeholder = mustache_remover_placeholder
self.mustache_remover = Jinja2MustacheRemover(templates_include_dir) if mustache_remover_name == 'jinja2' else PybarMustacheRemover()

def validate(self, files=None, remove_mustaches=False, **kwargs):
Expand All @@ -68,19 +77,19 @@ def validate(self, files=None, remove_mustaches=False, **kwargs):
with generate_mustachefree_tmpfiles(files,
self.mustache_remover,
copy_ext=self.mustache_remover_copy_ext,
default_value=self.mustache_remover_default_value) as tmpfiles:
placeholder=self.mustache_remover_placeholder) as tmpfiles:
return Validator.validate(self, tmpfiles, **kwargs)
else:
return Validator.validate(self, files, **kwargs)

@contextlib.contextmanager
def generate_mustachefree_tmpfiles(filepaths, mustache_remover, copy_ext, default_value):
def generate_mustachefree_tmpfiles(filepaths, mustache_remover, copy_ext, placeholder):
mustachefree_tmpfiles = []

for filepath in filepaths:
tmpfile = filepath + copy_ext
shutil.copyfile(filepath, tmpfile)
code_without_mustaches = mustache_remover.clean_template(filepath, default_value)
code_without_mustaches = mustache_remover.clean_template(filepath, placeholder)
with open(tmpfile, 'w+') as new_tmpfile:
new_tmpfile.write(code_without_mustaches)
mustachefree_tmpfiles.append(tmpfile)
Expand All @@ -95,54 +104,65 @@ def generate_mustachefree_tmpfiles(filepaths, mustache_remover, copy_ext, defaul
class PybarMustacheRemover:
def __init__(self):
self.tmplt_compiler = PybarCompiler()
def clean_template(self, filepath, default_value):
def clean_template(self, filepath, placeholder):
with open(filepath, 'r') as src_file:
template_content = text_type(src_file.read())
try:
compiled_template = self.tmplt_compiler.compile(template_content)
return compiled_template(RecursiveDefaultPlaceholder(default_value))
return compiled_template(PybarPlaceholderContext(placeholder))
except PybarsError as error:
raise_from(MustacheSubstitutionFail('For HTML template file {}: {}'.format(filepath, error)), error)

class RecursiveDefaultPlaceholder:
def __init__(self, default):
self.default = default
def __str__(self):
return str(self.default)
def __getattribute__(self, name):
if name == 'default' or name.startswith('__'):
return object.__getattribute__(self, name)
return self
def __iter__(self):
return iter([self, self])
def __getitem__(self, _):
return self
class PybarPlaceholderContext:
def __init__(self, placeholder):
self.placeholder = placeholder
def get(self, segment):
if segment in self.placeholder.env:
return self.placeholder.env[segment]
return RecursiveDefaultPlaceholder(self.placeholder.default_value)


class Jinja2MustacheRemover:
def __init__(self, templates_include_dir):
self.template_loader_extra_paths = [templates_include_dir] if templates_include_dir else []
def clean_template(self, filepath, default_value):
env = Jinja2PlaceholderEnvironment(default_value, loader=FileSystemLoader([os.path.dirname(filepath)] + self.template_loader_extra_paths))
def clean_template(self, filepath, placeholder):
env = Jinja2PlaceholderEnvironment(placeholder, loader=FileSystemLoader([os.path.dirname(filepath)] + self.template_loader_extra_paths))
template = env.get_template(os.path.basename(filepath))
context = Jinja2PlaceholderContext(default_value, env, DEFAULT_NAMESPACE.copy(), template.name, template.blocks)
context = Jinja2PlaceholderContext(placeholder, env, DEFAULT_NAMESPACE.copy(), template.name, template.blocks)
return concat(template.root_render_func(context))

class Jinja2PlaceholderEnvironment(Environment):
def __init__(self, default, *args, **kwargs):
def __init__(self, placeholder, *args, **kwargs):
Environment.__init__(self, *args, **kwargs)
self.default = default
self.placeholder = placeholder
def getattr(self, *_, **__):
return RecursiveDefaultPlaceholder(self.default)
return RecursiveDefaultPlaceholder(self.placeholder.default_value)

class Jinja2PlaceholderContext(Context):
def __init__(self, default, *args, **kwargs):
def __init__(self, placeholder, *args, **kwargs):
Context.__init__(self, *args, **kwargs)
self.default = default
self.placeholder = placeholder
def call(self, *_, **__):
return RecursiveDefaultPlaceholder(self.default)
def resolve_or_missing(self, *_, **__):
return RecursiveDefaultPlaceholder(self.default)
return RecursiveDefaultPlaceholder(self.placeholder.default_value)
def resolve_or_missing(self, key, missing=None):
if key in self.placeholder.env:
return self.placeholder.env[key]
return RecursiveDefaultPlaceholder(self.placeholder.default_value)


class RecursiveDefaultPlaceholder:
def __init__(self, default):
self.default = default
def __str__(self):
return str(self.default)
def __getattribute__(self, name):
if name == 'default' or name.startswith('__'):
return object.__getattribute__(self, name)
return self
def __iter__(self):
return iter([self, self])
def __getitem__(self, _):
return self


class MustacheSubstitutionFail(Exception):
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
name='pre-commit-hooks',
description='A pre-commit hook to validate your HTML files / templates against the W3C v.Nu checker',
url='https://github.com/Lucas-C/pre-commit-hooks-html',
version='1.3.4',
version='1.3.5',

author='Lucas Cimon',
author_email='lucas.cimon@gmail.com',
Expand Down
15 changes: 12 additions & 3 deletions tests/validate_html_test.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import absolute_import
from __future__ import unicode_literals

from pre_commit_hooks.validate_html import Jinja2MustacheRemover, main as validate_html
from pre_commit_hooks.validate_html import Jinja2MustacheRemover, Placeholder, PybarMustacheRemover, main as validate_html


HTML_WITH_HANDLEBAR_TITLE = '''<!DOCTYPE html>
Expand All @@ -16,8 +16,8 @@
</html>'''


def test_jinja2mustacheremover():
assert Jinja2MustacheRemover('tests').clean_template('tests/jinja-template.html', 'DUMMY') == '''base.html content
def test_Jinja2MustacheRemover():
assert Jinja2MustacheRemover('tests').clean_template('tests/jinja-template.html', Placeholder('DUMMY')) == '''base.html content
Jinja test
DUMMY
Expand All @@ -31,6 +31,15 @@ def test_jinja2mustacheremover():
partial.html content
'''

def test_Jinja2MustacheRemover_providedEnv(tmpdir):
html_file = tmpdir.join('test.html')
html_file.write('{{x}}')
assert Jinja2MustacheRemover('tests').clean_template(html_file.strpath, Placeholder('DUMMY', (('x', '"42"'),))) == '42'

def test_PybarMustacheRemover_providedEnv(tmpdir):
hbs_file = tmpdir.join('test.hbs')
hbs_file.write('{{x}}')
assert PybarMustacheRemover().clean_template(hbs_file.strpath, Placeholder('DUMMY', (('x', '42'),))) == '42'

def test_validate_pybar_ok(tmpdir, caplog):
hbs_file = tmpdir.join('test.hbs')
Expand Down

0 comments on commit b19f083

Please sign in to comment.