From d25b1414514d5823ff79f46dbf13d17abc9b540e Mon Sep 17 00:00:00 2001 From: Emil Date: Sun, 14 Jun 2020 11:37:50 +0300 Subject: [PATCH 1/5] :sparkles: Expand list with extensions for template rendering Signed-off-by: Emil --- frappe/utils/jinja.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py index 2863ec99cd..97c7bf6127 100644 --- a/frappe/utils/jinja.py +++ b/frappe/utils/jinja.py @@ -90,7 +90,7 @@ def guess_is_path(template): # if its single line and ends with a html, then its probably a path if not '\n' in template and '.' in template: extn = template.rsplit('.')[-1] - if extn in ('html', 'css', 'scss', 'py'): + if extn in ('html', 'css', 'scss', 'py', 'md', 'json', 'js', 'xml'): return True return False From 3bc66bfea1ceb6252ced09b36dcbea16e3c17160 Mon Sep 17 00:00:00 2001 From: Emil Date: Sun, 14 Jun 2020 12:28:21 +0300 Subject: [PATCH 2/5] :sparkles: add another way to check path Signed-off-by: Emil --- frappe/utils/jinja.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py index 97c7bf6127..f7eb1a2eb8 100644 --- a/frappe/utils/jinja.py +++ b/frappe/utils/jinja.py @@ -2,6 +2,9 @@ # MIT License. See license.txt from __future__ import unicode_literals +import os + + def get_jenv(): import frappe from frappe.utils.safe_exec import get_safe_globals @@ -75,7 +78,7 @@ def render_template(template, context, is_path=None, safe_render=True): if not template: return "" - if (is_path or guess_is_path(template)): + if is_path or os.path.exists(template): return get_jenv().get_template(template).render(context) else: if safe_render and ".__" in template: @@ -85,16 +88,6 @@ def render_template(template, context, is_path=None, safe_render=True): except TemplateError: throw(title="Jinja Template Error", msg="
{template}
{tb}
".format(template=template, tb=get_traceback())) -def guess_is_path(template): - # template can be passed as a path or content - # if its single line and ends with a html, then its probably a path - if not '\n' in template and '.' in template: - extn = template.rsplit('.')[-1] - if extn in ('html', 'css', 'scss', 'py', 'md', 'json', 'js', 'xml'): - return True - - return False - def get_jloader(): import frappe From 267d3119f13541a6053b22032c09a51a9c2b8001 Mon Sep 17 00:00:00 2001 From: Emil Date: Sun, 14 Jun 2020 13:26:43 +0300 Subject: [PATCH 3/5] :bug: Return way of checking path Signed-off-by: Emil --- frappe/utils/jinja.py | 300 ++++++++++++++++++++++-------------------- 1 file changed, 158 insertions(+), 142 deletions(-) diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py index f7eb1a2eb8..507ecb0d4c 100644 --- a/frappe/utils/jinja.py +++ b/frappe/utils/jinja.py @@ -2,69 +2,71 @@ # MIT License. See license.txt from __future__ import unicode_literals -import os - def get_jenv(): - import frappe - from frappe.utils.safe_exec import get_safe_globals + import frappe + from frappe.utils.safe_exec import get_safe_globals - if not getattr(frappe.local, 'jenv', None): - from jinja2 import DebugUndefined - from jinja2.sandbox import SandboxedEnvironment + if not getattr(frappe.local, 'jenv', None): + from jinja2 import DebugUndefined + from jinja2.sandbox import SandboxedEnvironment - # frappe will be loaded last, so app templates will get precedence - jenv = SandboxedEnvironment( - loader=get_jloader(), - undefined=DebugUndefined - ) - set_filters(jenv) + # frappe will be loaded last, so app templates will get precedence + jenv = SandboxedEnvironment( + loader=get_jloader(), + undefined=DebugUndefined + ) + set_filters(jenv) - jenv.globals.update(get_safe_globals()) - jenv.globals.update(get_jenv_customization('methods')) - jenv.globals.update({ - 'resolve_class': resolve_class, - 'inspect': inspect, - 'web_blocks': web_blocks - }) + jenv.globals.update(get_safe_globals()) + jenv.globals.update(get_jenv_customization('methods')) + jenv.globals.update({ + 'resolve_class': resolve_class, + 'inspect': inspect, + 'web_blocks': web_blocks + }) - frappe.local.jenv = jenv + frappe.local.jenv = jenv + + return frappe.local.jenv - return frappe.local.jenv def get_template(path): - return get_jenv().get_template(path) + return get_jenv().get_template(path) + def get_email_from_template(name, args): - from jinja2 import TemplateNotFound + from jinja2 import TemplateNotFound - args = args or {} - try: - message = get_template('templates/emails/' + name + '.html').render(args) - except TemplateNotFound as e: - raise e + args = args or {} + try: + message = get_template('templates/emails/' + name + '.html').render(args) + except TemplateNotFound as e: + raise e - try: - text_content = get_template('templates/emails/' + name + '.txt').render(args) - except TemplateNotFound: - text_content = None + try: + text_content = get_template('templates/emails/' + name + '.txt').render(args) + except TemplateNotFound: + text_content = None + + return (message, text_content) - return (message, text_content) def validate_template(html): - """Throws exception if there is a syntax error in the Jinja Template""" - import frappe - from jinja2 import TemplateSyntaxError + """Throws exception if there is a syntax error in the Jinja Template""" + import frappe + from jinja2 import TemplateSyntaxError + + jenv = get_jenv() + try: + jenv.from_string(html) + except TemplateSyntaxError as e: + frappe.msgprint('Line {}: {}'.format(e.lineno, e.message)) + frappe.throw(frappe._("Syntax error in template")) - jenv = get_jenv() - try: - jenv.from_string(html) - except TemplateSyntaxError as e: - frappe.msgprint('Line {}: {}'.format(e.lineno, e.message)) - frappe.throw(frappe._("Syntax error in template")) def render_template(template, context, is_path=None, safe_render=True): - '''Render a template using Jinja + '''Render a template using Jinja :param template: path or HTML containing the jinja template :param context: dict of properties to pass to the template @@ -72,141 +74,155 @@ def render_template(template, context, is_path=None, safe_render=True): :param safe_render: (optional) prevent server side scripting via jinja templating ''' - from frappe import get_traceback, throw - from jinja2 import TemplateError + from frappe import get_traceback, throw + from jinja2 import TemplateError - if not template: - return "" + if not template: + return "" - if is_path or os.path.exists(template): - return get_jenv().get_template(template).render(context) - else: - if safe_render and ".__" in template: - throw("Illegal template") - try: - return get_jenv().from_string(template).render(context) - except TemplateError: - throw(title="Jinja Template Error", msg="
{template}
{tb}
".format(template=template, tb=get_traceback())) + if is_path or guess_is_path(template): + return get_jenv().get_template(template).render(context) + else: + if safe_render and ".__" in template: + throw("Illegal template") + try: + return get_jenv().from_string(template).render(context) + except TemplateError: + throw(title="Jinja Template Error", + msg="
{template}
{tb}
".format(template=template, tb=get_traceback())) + + +def guess_is_path(template): + # template can be passed as a path or content + # if its single line and ends with a html, then its probably a path + if not '\n' in template and '.' in template: + extn = template.rsplit('.')[-1] + if extn in ('html', 'css', 'scss', 'py', 'md', 'json', 'js', 'xml'): + return True + + return False def get_jloader(): - import frappe - if not getattr(frappe.local, 'jloader', None): - from jinja2 import ChoiceLoader, PackageLoader, PrefixLoader + import frappe + if not getattr(frappe.local, 'jloader', None): + from jinja2 import ChoiceLoader, PackageLoader, PrefixLoader - if frappe.local.flags.in_setup_help: - apps = ['frappe'] - else: - apps = frappe.get_hooks('template_apps') - if not apps: - apps = frappe.local.flags.web_pages_apps or frappe.get_installed_apps(sort=True) - apps.reverse() + if frappe.local.flags.in_setup_help: + apps = ['frappe'] + else: + apps = frappe.get_hooks('template_apps') + if not apps: + apps = frappe.local.flags.web_pages_apps or frappe.get_installed_apps(sort=True) + apps.reverse() - if not "frappe" in apps: - apps.append('frappe') + if not "frappe" in apps: + apps.append('frappe') - frappe.local.jloader = ChoiceLoader( - # search for something like app/templates/... - [PrefixLoader(dict( - (app, PackageLoader(app, ".")) for app in apps - ))] + frappe.local.jloader = ChoiceLoader( + # search for something like app/templates/... + [PrefixLoader(dict( + (app, PackageLoader(app, ".")) for app in apps + ))] - # search for something like templates/... - + [PackageLoader(app, ".") for app in apps] - ) + # search for something like templates/... + + [PackageLoader(app, ".") for app in apps] + ) + + return frappe.local.jloader - return frappe.local.jloader def set_filters(jenv): - import frappe - from frappe.utils import global_date_format, cint, cstr, flt, markdown - from frappe.website.utils import get_shade, abs_url + import frappe + from frappe.utils import global_date_format, cint, cstr, flt, markdown + from frappe.website.utils import get_shade, abs_url - jenv.filters["global_date_format"] = global_date_format - jenv.filters["markdown"] = markdown - jenv.filters["json"] = frappe.as_json - jenv.filters["get_shade"] = get_shade - jenv.filters["len"] = len - jenv.filters["int"] = cint - jenv.filters["str"] = cstr - jenv.filters["flt"] = flt - jenv.filters["abs_url"] = abs_url + jenv.filters["global_date_format"] = global_date_format + jenv.filters["markdown"] = markdown + jenv.filters["json"] = frappe.as_json + jenv.filters["get_shade"] = get_shade + jenv.filters["len"] = len + jenv.filters["int"] = cint + jenv.filters["str"] = cstr + jenv.filters["flt"] = flt + jenv.filters["abs_url"] = abs_url - if frappe.flags.in_setup_help: - return + if frappe.flags.in_setup_help: + return - jenv.filters.update(get_jenv_customization('filters')) + jenv.filters.update(get_jenv_customization('filters')) def get_jenv_customization(customization_type): - '''Returns a dict with filter/method name as key and definition as value''' + '''Returns a dict with filter/method name as key and definition as value''' - import frappe + import frappe - out = {} - if not getattr(frappe.local, "site", None): - return out + out = {} + if not getattr(frappe.local, "site", None): + return out - values = frappe.get_hooks("jenv", {}).get(customization_type) - if not values: - return out + values = frappe.get_hooks("jenv", {}).get(customization_type) + if not values: + return out - for value in values: - fn_name, fn_string = value.split(":") - out[fn_name] = frappe.get_attr(fn_string) + for value in values: + fn_name, fn_string = value.split(":") + out[fn_name] = frappe.get_attr(fn_string) - return out + return out def resolve_class(classes): - import frappe + import frappe - if classes is None: - return '' + if classes is None: + return '' - if isinstance(classes, frappe.string_types): - return classes + if isinstance(classes, frappe.string_types): + return classes - if isinstance(classes, (list, tuple)): - return ' '.join([resolve_class(c) for c in classes]).strip() + if isinstance(classes, (list, tuple)): + return ' '.join([resolve_class(c) for c in classes]).strip() - if isinstance(classes, dict): - return ' '.join([classname for classname in classes if classes[classname]]).strip() + if isinstance(classes, dict): + return ' '.join([classname for classname in classes if classes[classname]]).strip() - return classes + return classes def inspect(var, render=True): - context = { "var": var } - if render: - html = "
{{ var | pprint | e }}
" - else: - html = "" - return get_jenv().from_string(html).render(context) + context = {"var": var} + if render: + html = "
{{ var | pprint | e }}
" + else: + html = "" + return get_jenv().from_string(html).render(context) + def web_blocks(blocks): - from frappe import get_doc - from frappe.website.doctype.web_page.web_page import get_web_blocks_html + from frappe import get_doc + from frappe.website.doctype.web_page.web_page import get_web_blocks_html - web_blocks = [] - for block in blocks: - doc = { - 'doctype': 'Web Page Block', - 'web_template': block['template'], - 'web_template_values': block['values'], - 'add_top_padding': 1, - 'add_bottom_padding': 1, - 'add_container': 1, - 'hide_block': 0, - 'css_class': '' - } - doc.update(block) - web_blocks.append(get_doc(doc)) + web_blocks = [] + for block in blocks: + doc = { + 'doctype': 'Web Page Block', + 'web_template': block['template'], + 'web_template_values': block['values'], + 'add_top_padding': 1, + 'add_bottom_padding': 1, + 'add_container': 1, + 'hide_block': 0, + 'css_class': '' + } + doc.update(block) + web_blocks.append(get_doc(doc)) - out = get_web_blocks_html(web_blocks) + out = get_web_blocks_html(web_blocks) - html = out.html - for script in out.scripts: - html += ''.format(script) + html = out.html + for script in out.scripts: + html += ''.format(script) - return html + return html From 8a9ba931199c4e51ee3400402225dcaeb924c981 Mon Sep 17 00:00:00 2001 From: Emil Date: Sun, 14 Jun 2020 14:31:17 +0300 Subject: [PATCH 4/5] :art: change construction for not in Signed-off-by: Emil --- frappe/utils/jinja.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py index 507ecb0d4c..b4b2c26bc7 100644 --- a/frappe/utils/jinja.py +++ b/frappe/utils/jinja.py @@ -95,7 +95,7 @@ def render_template(template, context, is_path=None, safe_render=True): def guess_is_path(template): # template can be passed as a path or content # if its single line and ends with a html, then its probably a path - if not '\n' in template and '.' in template: + if '\n' not in template and '.' in template: extn = template.rsplit('.')[-1] if extn in ('html', 'css', 'scss', 'py', 'md', 'json', 'js', 'xml'): return True @@ -116,7 +116,7 @@ def get_jloader(): apps = frappe.local.flags.web_pages_apps or frappe.get_installed_apps(sort=True) apps.reverse() - if not "frappe" in apps: + if "frappe" not in apps: apps.append('frappe') frappe.local.jloader = ChoiceLoader( From edcdb66b92516c99cfd0dbc4582c886f90b11138 Mon Sep 17 00:00:00 2001 From: Emil Date: Mon, 15 Jun 2020 12:30:44 +0300 Subject: [PATCH 5/5] :art: Change indetions to tabs Signed-off-by: Emil --- frappe/utils/jinja.py | 303 ++++++++++++++++++++---------------------- 1 file changed, 147 insertions(+), 156 deletions(-) diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py index b4b2c26bc7..8653cdc30a 100644 --- a/frappe/utils/jinja.py +++ b/frappe/utils/jinja.py @@ -2,71 +2,66 @@ # MIT License. See license.txt from __future__ import unicode_literals - def get_jenv(): - import frappe - from frappe.utils.safe_exec import get_safe_globals + import frappe + from frappe.utils.safe_exec import get_safe_globals - if not getattr(frappe.local, 'jenv', None): - from jinja2 import DebugUndefined - from jinja2.sandbox import SandboxedEnvironment + if not getattr(frappe.local, 'jenv', None): + from jinja2 import DebugUndefined + from jinja2.sandbox import SandboxedEnvironment - # frappe will be loaded last, so app templates will get precedence - jenv = SandboxedEnvironment( - loader=get_jloader(), - undefined=DebugUndefined - ) - set_filters(jenv) + # frappe will be loaded last, so app templates will get precedence + jenv = SandboxedEnvironment( + loader=get_jloader(), + undefined=DebugUndefined + ) + set_filters(jenv) - jenv.globals.update(get_safe_globals()) - jenv.globals.update(get_jenv_customization('methods')) - jenv.globals.update({ - 'resolve_class': resolve_class, - 'inspect': inspect, - 'web_blocks': web_blocks - }) + jenv.globals.update(get_safe_globals()) + jenv.globals.update(get_jenv_customization('methods')) + jenv.globals.update({ + 'resolve_class': resolve_class, + 'inspect': inspect, + 'web_blocks': web_blocks + }) - frappe.local.jenv = jenv - - return frappe.local.jenv + frappe.local.jenv = jenv + return frappe.local.jenv def get_template(path): - return get_jenv().get_template(path) - + return get_jenv().get_template(path) def get_email_from_template(name, args): - from jinja2 import TemplateNotFound + from jinja2 import TemplateNotFound - args = args or {} - try: - message = get_template('templates/emails/' + name + '.html').render(args) - except TemplateNotFound as e: - raise e + args = args or {} + try: + message = get_template('templates/emails/' + name + '.html').render(args) + except TemplateNotFound as e: + raise e - try: - text_content = get_template('templates/emails/' + name + '.txt').render(args) - except TemplateNotFound: - text_content = None - - return (message, text_content) + try: + text_content = get_template('templates/emails/' + name + '.txt').render(args) + except TemplateNotFound: + text_content = None + return (message, text_content) def validate_template(html): - """Throws exception if there is a syntax error in the Jinja Template""" - import frappe - from jinja2 import TemplateSyntaxError - - jenv = get_jenv() - try: - jenv.from_string(html) - except TemplateSyntaxError as e: - frappe.msgprint('Line {}: {}'.format(e.lineno, e.message)) - frappe.throw(frappe._("Syntax error in template")) + """Throws exception if there is a syntax error in the Jinja Template""" + import frappe + from jinja2 import TemplateSyntaxError + jenv = get_jenv() + try: + jenv.from_string(html) + except TemplateSyntaxError as e: + frappe.msgprint('Line {}: {}'.format(e.lineno, e.message)) + frappe.throw(frappe._("Syntax error in template")) def render_template(template, context, is_path=None, safe_render=True): - '''Render a template using Jinja + '''Render a template using Jinja :param template: path or HTML containing the jinja template :param context: dict of properties to pass to the template @@ -74,155 +69,151 @@ def render_template(template, context, is_path=None, safe_render=True): :param safe_render: (optional) prevent server side scripting via jinja templating ''' - from frappe import get_traceback, throw - from jinja2 import TemplateError + from frappe import get_traceback, throw + from jinja2 import TemplateError - if not template: - return "" - - if is_path or guess_is_path(template): - return get_jenv().get_template(template).render(context) - else: - if safe_render and ".__" in template: - throw("Illegal template") - try: - return get_jenv().from_string(template).render(context) - except TemplateError: - throw(title="Jinja Template Error", - msg="
{template}
{tb}
".format(template=template, tb=get_traceback())) + if not template: + return "" + if (is_path or guess_is_path(template)): + return get_jenv().get_template(template).render(context) + else: + if safe_render and ".__" in template: + throw("Illegal template") + try: + return get_jenv().from_string(template).render(context) + except TemplateError: + throw(title="Jinja Template Error", msg="
{template}
{tb}
".format(template=template, tb=get_traceback())) def guess_is_path(template): - # template can be passed as a path or content - # if its single line and ends with a html, then its probably a path - if '\n' not in template and '.' in template: - extn = template.rsplit('.')[-1] - if extn in ('html', 'css', 'scss', 'py', 'md', 'json', 'js', 'xml'): - return True + # template can be passed as a path or content + # if its single line and ends with a html, then its probably a path + if '\n' not in template and '.' in template: + extn = template.rsplit('.')[-1] + if extn in ('html', 'css', 'scss', 'py', 'md', 'json', 'js', 'xml'): + return True - return False + return False def get_jloader(): - import frappe - if not getattr(frappe.local, 'jloader', None): - from jinja2 import ChoiceLoader, PackageLoader, PrefixLoader + import frappe + if not getattr(frappe.local, 'jloader', None): + from jinja2 import ChoiceLoader, PackageLoader, PrefixLoader - if frappe.local.flags.in_setup_help: - apps = ['frappe'] - else: - apps = frappe.get_hooks('template_apps') - if not apps: - apps = frappe.local.flags.web_pages_apps or frappe.get_installed_apps(sort=True) - apps.reverse() + if frappe.local.flags.in_setup_help: + apps = ['frappe'] + else: + apps = frappe.get_hooks('template_apps') + if not apps: + apps = frappe.local.flags.web_pages_apps or frappe.get_installed_apps(sort=True) + apps.reverse() - if "frappe" not in apps: - apps.append('frappe') + if "frappe" not in apps: + apps.append('frappe') - frappe.local.jloader = ChoiceLoader( - # search for something like app/templates/... - [PrefixLoader(dict( - (app, PackageLoader(app, ".")) for app in apps - ))] + frappe.local.jloader = ChoiceLoader( + # search for something like app/templates/... + [PrefixLoader(dict( + (app, PackageLoader(app, ".")) for app in apps + ))] - # search for something like templates/... - + [PackageLoader(app, ".") for app in apps] - ) - - return frappe.local.jloader + # search for something like templates/... + + [PackageLoader(app, ".") for app in apps] + ) + return frappe.local.jloader def set_filters(jenv): - import frappe - from frappe.utils import global_date_format, cint, cstr, flt, markdown - from frappe.website.utils import get_shade, abs_url + import frappe + from frappe.utils import global_date_format, cint, cstr, flt, markdown + from frappe.website.utils import get_shade, abs_url - jenv.filters["global_date_format"] = global_date_format - jenv.filters["markdown"] = markdown - jenv.filters["json"] = frappe.as_json - jenv.filters["get_shade"] = get_shade - jenv.filters["len"] = len - jenv.filters["int"] = cint - jenv.filters["str"] = cstr - jenv.filters["flt"] = flt - jenv.filters["abs_url"] = abs_url + jenv.filters["global_date_format"] = global_date_format + jenv.filters["markdown"] = markdown + jenv.filters["json"] = frappe.as_json + jenv.filters["get_shade"] = get_shade + jenv.filters["len"] = len + jenv.filters["int"] = cint + jenv.filters["str"] = cstr + jenv.filters["flt"] = flt + jenv.filters["abs_url"] = abs_url - if frappe.flags.in_setup_help: - return + if frappe.flags.in_setup_help: + return - jenv.filters.update(get_jenv_customization('filters')) + jenv.filters.update(get_jenv_customization('filters')) def get_jenv_customization(customization_type): - '''Returns a dict with filter/method name as key and definition as value''' + '''Returns a dict with filter/method name as key and definition as value''' - import frappe + import frappe - out = {} - if not getattr(frappe.local, "site", None): - return out + out = {} + if not getattr(frappe.local, "site", None): + return out - values = frappe.get_hooks("jenv", {}).get(customization_type) - if not values: - return out + values = frappe.get_hooks("jenv", {}).get(customization_type) + if not values: + return out - for value in values: - fn_name, fn_string = value.split(":") - out[fn_name] = frappe.get_attr(fn_string) + for value in values: + fn_name, fn_string = value.split(":") + out[fn_name] = frappe.get_attr(fn_string) - return out + return out def resolve_class(classes): - import frappe + import frappe - if classes is None: - return '' + if classes is None: + return '' - if isinstance(classes, frappe.string_types): - return classes + if isinstance(classes, frappe.string_types): + return classes - if isinstance(classes, (list, tuple)): - return ' '.join([resolve_class(c) for c in classes]).strip() + if isinstance(classes, (list, tuple)): + return ' '.join([resolve_class(c) for c in classes]).strip() - if isinstance(classes, dict): - return ' '.join([classname for classname in classes if classes[classname]]).strip() + if isinstance(classes, dict): + return ' '.join([classname for classname in classes if classes[classname]]).strip() - return classes + return classes def inspect(var, render=True): - context = {"var": var} - if render: - html = "
{{ var | pprint | e }}
" - else: - html = "" - return get_jenv().from_string(html).render(context) - + context = { "var": var } + if render: + html = "
{{ var | pprint | e }}
" + else: + html = "" + return get_jenv().from_string(html).render(context) def web_blocks(blocks): - from frappe import get_doc - from frappe.website.doctype.web_page.web_page import get_web_blocks_html + from frappe import get_doc + from frappe.website.doctype.web_page.web_page import get_web_blocks_html - web_blocks = [] - for block in blocks: - doc = { - 'doctype': 'Web Page Block', - 'web_template': block['template'], - 'web_template_values': block['values'], - 'add_top_padding': 1, - 'add_bottom_padding': 1, - 'add_container': 1, - 'hide_block': 0, - 'css_class': '' - } - doc.update(block) - web_blocks.append(get_doc(doc)) + web_blocks = [] + for block in blocks: + doc = { + 'doctype': 'Web Page Block', + 'web_template': block['template'], + 'web_template_values': block['values'], + 'add_top_padding': 1, + 'add_bottom_padding': 1, + 'add_container': 1, + 'hide_block': 0, + 'css_class': '' + } + doc.update(block) + web_blocks.append(get_doc(doc)) - out = get_web_blocks_html(web_blocks) + out = get_web_blocks_html(web_blocks) - html = out.html - for script in out.scripts: - html += ''.format(script) + html = out.html + for script in out.scripts: + html += ''.format(script) - return html + return html