Skip to content

Commit eec18df

Browse files
committed
v0.8.0a3: Fixes & backwards compatibility
- Allow undefined variables in templates & preprocessor by default. Define config file settings & CLI flags to change this. - Allow --bypass_errors to skip over duplicate YAML keys.
1 parent 874c6a8 commit eec18df

File tree

6 files changed

+56
-20
lines changed

6 files changed

+56
-20
lines changed

dactyl/cli.py

+6
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ def __init__(self, utility):
7676
help="Don't automatically add a cover / index file.")
7777
parser.add_argument("--skip_preprocessor", action="store_true", default=False,
7878
help="Don't pre-process Jinja syntax in markdown files")
79+
parser.add_argument("--template_strict_undefined", action="store_true",
80+
help="Raise an error on undefined variables in "+
81+
"template syntax.")
82+
parser.add_argument("--pp_strict_undefined", action="store_true",
83+
help="Raise an error on undefined variables in "+
84+
"preprocessor syntax.")
7985
parser.add_argument("--title", type=str, help="Override target display "+\
8086
"name. Useful when passing multiple args to --pages.")
8187
parser.add_argument("--vars", type=str, help="A YAML or JSON file with vars "+

dactyl/config.py

+7
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ def __init__(self, cli_args):
2727
exit(0)
2828

2929
self.bypass_errors = cli_args.bypass_errors
30+
if self.bypass_errors:
31+
yaml.allow_duplicate_keys = True
3032

3133
# Start with the default config, then overwrite later
3234
self.config = yaml.load(resource_stream(__name__, "default-config.yml"))
@@ -183,6 +185,11 @@ def load_build_options(self):
183185

184186
self.config["skip_preprocessor"] = self.cli_args.skip_preprocessor
185187

188+
if self.cli_args.template_strict_undefined:
189+
self.config["template_allow_undefined"] = False
190+
if self.cli_args.pp_strict_undefined:
191+
self.config["preprocessor_allow_undefined"] = False
192+
186193
def html_filename_from(self, page):
187194
"""Take a page definition and choose a reasonable HTML filename for it."""
188195
if "md" in page:

dactyl/dactyl_build.py

+36-18
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,11 @@ def preprocess_markdown(page, target=None, categories=[], page_filters=[],
318318
md = f.read()
319319

320320
else:
321-
pp_env = setup_pp_env(page, page_filters=page_filters, bypass_errors=bypass_errors)
321+
if config["preprocessor_allow_undefined"] == False and not bypass_errors:
322+
strict_undefined = True
323+
else:
324+
strict_undefined = False
325+
pp_env = setup_pp_env(page, page_filters=page_filters, strict_undefined=strict_undefined)
322326
md_raw = pp_env.get_template(page["md"])
323327
md = md_raw.render(
324328
currentpage=page,
@@ -435,12 +439,12 @@ def get_page_where(page=None):
435439
return False, config["content_path"]
436440

437441

438-
def setup_pp_env(page=None, page_filters=[], no_loader=False, bypass_errors=False):
442+
def setup_pp_env(page=None, page_filters=[], no_loader=False, strict_undefined=False):
439443
remote, path = get_page_where(page)
440-
if bypass_errors:
441-
preferred_undefined = jinja2.Undefined
442-
else:
444+
if strict_undefined:
443445
preferred_undefined = jinja2.StrictUndefined
446+
else:
447+
preferred_undefined = jinja2.Undefined
444448
if remote:
445449
logger.debug("Using remote template loader for page %s" % page)
446450
pp_env = jinja2.Environment(undefined=preferred_undefined,
@@ -473,29 +477,35 @@ def undefined_or_ne(a,b):
473477
return pp_env
474478

475479

476-
def setup_html_env(bypass_errors=False):
477-
if bypass_errors:
478-
preferred_undefined = jinja2.Undefined
479-
else:
480+
def setup_html_env(strict_undefined=False):
481+
if strict_undefined:
480482
preferred_undefined = jinja2.StrictUndefined
483+
else:
484+
preferred_undefined = jinja2.Undefined
481485
if "template_path" in config:
482486
env = jinja2.Environment(undefined=preferred_undefined,
483487
loader=jinja2.FileSystemLoader(config["template_path"]))
484-
# add custom "defined_and_" tests
485-
def defined_and_equalto(a,b):
486-
return env.tests["defined"](a) and env.tests["equalto"](a, b)
487-
env.tests["defined_and_equalto"] = defined_and_equalto
488-
def undefined_or_ne(a,b):
489-
return env.tests["undefined"](a) or env.tests["ne"](a, b)
490-
env.tests["undefined_or_ne"] = undefined_or_ne
491488
else:
492489
env = setup_fallback_env()
490+
491+
# Customize env: add custom tests, lstrip & trim blocks
492+
def defined_and_equalto(a,b):
493+
return env.tests["defined"](a) and env.tests["equalto"](a, b)
494+
env.tests["defined_and_equalto"] = defined_and_equalto
495+
def undefined_or_ne(a,b):
496+
return env.tests["undefined"](a) or env.tests["ne"](a, b)
497+
env.tests["undefined_or_ne"] = undefined_or_ne
498+
493499
env.lstrip_blocks = True
494500
env.trim_blocks = True
495501
return env
496502

497503

498504
def setup_fallback_env():
505+
"""
506+
Set up a Jinja env to load templates from the package. These templates
507+
assume that we're not using StrictUndefined.
508+
"""
499509
env = jinja2.Environment(loader=jinja2.PackageLoader(__name__))
500510
env.lstrip_blocks = True
501511
env.trim_blocks = True
@@ -669,7 +679,11 @@ def render_es_json(currentpage, es_template, pages=[], target=None, categories=[
669679
"bypass_errors": bypass_errors,
670680
}
671681

672-
es_env = setup_pp_env(no_loader=True, bypass_errors=bypass_errors)
682+
if config["preprocessor_allow_undefined"] == False and not bypass_errors:
683+
strict_undefined = True
684+
else:
685+
strict_undefined = False
686+
es_env = setup_pp_env(no_loader=True, strict_undefined=strict_undefined)
673687

674688
def render_es_field(value, context):
675689
if type(value) == str: # jinja-render strings
@@ -741,8 +755,12 @@ def render_pages(target=None, mode="html", bypass_errors=False,
741755
# Note: this doesn't delete the old index
742756

743757
if mode == "pdf" or mode == "html":
758+
if config["template_allow_undefined"] == False and not bypass_errors:
759+
strict_undefined = True
760+
else:
761+
strict_undefined = False
744762
# Insert generated HTML into templates using this Jinja environment
745-
env = setup_html_env(bypass_errors=bypass_errors)
763+
env = setup_html_env(strict_undefined=strict_undefined)
746764
fallback_env = setup_fallback_env()
747765
if mode == "pdf":
748766
out_path = temp_files_path or temp_dir()

dactyl/default-config.yml

+6
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ prince_executable: prince
4343
## If this is true, parses the files as Markdown without Jinja syntax
4444
skip_preprocessor: false
4545

46+
## Set these to false to raise an error referring to a
47+
## field that doesn't exist, such as {{ foo }} or {% if foo %}
48+
## These settings are ignored when running with --bypass_errors.
49+
template_allow_undefined: true
50+
preprocessor_allow_undefined: true
51+
4652
## By default, generates HTML paths from md paths by replacing / with -
4753
## Set this to false to make default HTML paths mirror the folder structure of
4854
## the input md files.

dactyl/version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '0.8.0a2'
1+
__version__ = '0.8.0a3'

examples/plainlanguage_phrases.yaml

-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ it is essential: must, need to
5050
it is requested: please, we request, I request
5151
limited number: limits
5252
not later than: by, before
53-
not later than: by
5453
pertaining to: about, of, on
5554
prior to: before
5655
provided that: if

0 commit comments

Comments
 (0)