From 77e1773351d2fe062cfb785fecb1da388ac5535a Mon Sep 17 00:00:00 2001 From: DavidHuber Date: Mon, 22 Apr 2024 15:42:55 +0000 Subject: [PATCH 1/6] Add two new time filters to jinja --- src/wxflow/jinja.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/wxflow/jinja.py b/src/wxflow/jinja.py index 89d96e6..875cd2a 100644 --- a/src/wxflow/jinja.py +++ b/src/wxflow/jinja.py @@ -6,8 +6,8 @@ import jinja2 from markupsafe import Markup -from .timetools import (strftime, to_fv3time, to_isotime, to_julian, to_YMD, - to_YMDH) +from .timetools import (add_to_datetime, strftime, to_fv3time, to_isotime, + to_julian, to_timedelta, to_YMD, to_YMDH) __all__ = ['Jinja'] @@ -108,6 +108,8 @@ def get_set_env(self, loader: jinja2.BaseLoader, filters: Dict[str, callable] = to_f90bool: convert a boolean to a fortran boolean relpath: convert a full path to a relative path based on an input root_path getenv: read variable from environment if defined, else UNDEFINED + to_timedelta: convert a string to a timedelta object + add_to_datetime: add time to a datetime, return new datetime object Parameters ---------- @@ -131,6 +133,8 @@ def get_set_env(self, loader: jinja2.BaseLoader, filters: Dict[str, callable] = env.filters["to_f90bool"] = lambda bool: ".true." if bool else ".false." env.filters['getenv'] = lambda name, default='UNDEFINED': os.environ.get(name, default) env.filters["relpath"] = lambda pathname, start=os.curdir: os.path.relpath(pathname, start) + env.filters["add_to_datetime"] = lambda dt, delta: add_to_datetime(dt, delta) if not (isinstance(dt, SilentUndefined) or isinstance(delta, SilentUndefined)) else dt + env.filters["to_timedelta"] = lambda delta_str: to_timedelta(delta_str) if not isinstance(delta_str, SilentUndefined) else delta_str # Add any additional filters if filters is not None: From cdc9751680cb266bd29eaa4821eae919c6c901cc Mon Sep 17 00:00:00 2001 From: DavidHuber Date: Mon, 22 Apr 2024 15:49:40 +0000 Subject: [PATCH 2/6] Fix PEP8 line length. --- src/wxflow/jinja.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wxflow/jinja.py b/src/wxflow/jinja.py index 875cd2a..87aee04 100644 --- a/src/wxflow/jinja.py +++ b/src/wxflow/jinja.py @@ -133,7 +133,8 @@ def get_set_env(self, loader: jinja2.BaseLoader, filters: Dict[str, callable] = env.filters["to_f90bool"] = lambda bool: ".true." if bool else ".false." env.filters['getenv'] = lambda name, default='UNDEFINED': os.environ.get(name, default) env.filters["relpath"] = lambda pathname, start=os.curdir: os.path.relpath(pathname, start) - env.filters["add_to_datetime"] = lambda dt, delta: add_to_datetime(dt, delta) if not (isinstance(dt, SilentUndefined) or isinstance(delta, SilentUndefined)) else dt + env.filters["add_to_datetime"] = (lambda dt, delta: add_to_datetime(dt, delta) + if not (isinstance(dt, SilentUndefined) or isinstance(delta, SilentUndefined)) else dt) env.filters["to_timedelta"] = lambda delta_str: to_timedelta(delta_str) if not isinstance(delta_str, SilentUndefined) else delta_str # Add any additional filters From ae7f5ed38eac8c5d72dc0df7b739a4f9331a9404 Mon Sep 17 00:00:00 2001 From: DavidHuber Date: Tue, 30 Apr 2024 13:27:58 +0000 Subject: [PATCH 3/6] Add Template.substitute_structure to filters --- src/wxflow/jinja.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/wxflow/jinja.py b/src/wxflow/jinja.py index 87aee04..d17e6ab 100644 --- a/src/wxflow/jinja.py +++ b/src/wxflow/jinja.py @@ -110,6 +110,16 @@ def get_set_env(self, loader: jinja2.BaseLoader, filters: Dict[str, callable] = getenv: read variable from environment if defined, else UNDEFINED to_timedelta: convert a string to a timedelta object add_to_datetime: add time to a datetime, return new datetime object + template_substitute_structure: traverses a dictionary and substitutes + variables in fields, lists, and nested dictionaries + + Additionally, the following TemplateConstants are passed into the + environment: + DOLLAR_CURLY_BRACE + DOLLAR_PARENTHESES + DOUBLE_CURLY_BRACES + AT_SQUARE_BRACES + AT_ANGLE_BRACKETS Parameters ---------- @@ -124,6 +134,12 @@ def get_set_env(self, loader: jinja2.BaseLoader, filters: Dict[str, callable] = """ env = jinja2.Environment(loader=loader, undefined=self.undefined) + env["DOLLAR_CURLY_BRACE"} = TemplateConstants.DOLLAR_CURLY_BRACE + env["DOLLAR_PARENTHESES"} = TemplateConstants.DOLLAR_PARENTHESES + env["DOUBLE_CURLY_BRACES"} = TemplateConstants.DOUBLE_CURLY_BRACES + env["AT_SQUARE_BRACES"} = TemplateConstants.AT_SQUARE_BRACES + env["AT_ANGLE_BRACKETS"} = TemplateConstants.AT_ANGLE_BRACKETS + env.filters["strftime"] = lambda dt, fmt: strftime(dt, fmt) env.filters["to_isotime"] = lambda dt: to_isotime(dt) if not isinstance(dt, SilentUndefined) else dt env.filters["to_fv3time"] = lambda dt: to_fv3time(dt) if not isinstance(dt, SilentUndefined) else dt @@ -133,9 +149,22 @@ def get_set_env(self, loader: jinja2.BaseLoader, filters: Dict[str, callable] = env.filters["to_f90bool"] = lambda bool: ".true." if bool else ".false." env.filters['getenv'] = lambda name, default='UNDEFINED': os.environ.get(name, default) env.filters["relpath"] = lambda pathname, start=os.curdir: os.path.relpath(pathname, start) - env.filters["add_to_datetime"] = (lambda dt, delta: add_to_datetime(dt, delta) - if not (isinstance(dt, SilentUndefined) or isinstance(delta, SilentUndefined)) else dt) + env.filters["add_to_datetime"] = ( + lambda dt, delta: add_to_datetime(dt, delta) + if not (isinstance(dt, SilentUndefined) or isinstance(delta, SilentUndefined)) + else dt if isinstance(dt, SilentUndefined) else delta) env.filters["to_timedelta"] = lambda delta_str: to_timedelta(delta_str) if not isinstance(delta_str, SilentUndefined) else delta_str + env.filters["template_substitute_structure"] = ( + lambda structure_to_substitute, var_type, get_value: + Template.substitute_structure(structure_to_substitute, + var_type, + get_value) + if not (isinstance(structure_to_substitute, SilentUndefined) or + isinstance(var_type, SilentUndefined) or + isinstance(get_value, SilentUndefined)) + else structure_to_substitute if isinstance(structure_to_substitute, SlilentUndefined) + else var_type if isinstance(var_type, SilentUndefined) + else get_value) # Add any additional filters if filters is not None: From 36fd40d5137ed6619011da2c2081dd94b5b58258 Mon Sep 17 00:00:00 2001 From: DavidHuber Date: Tue, 30 Apr 2024 17:02:24 +0000 Subject: [PATCH 4/6] Fix template constants in jinja --- src/wxflow/jinja.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/wxflow/jinja.py b/src/wxflow/jinja.py index d17e6ab..abbc264 100644 --- a/src/wxflow/jinja.py +++ b/src/wxflow/jinja.py @@ -6,6 +6,7 @@ import jinja2 from markupsafe import Markup +from .template import TemplateConstants from .timetools import (add_to_datetime, strftime, to_fv3time, to_isotime, to_julian, to_timedelta, to_YMD, to_YMDH) @@ -134,11 +135,11 @@ def get_set_env(self, loader: jinja2.BaseLoader, filters: Dict[str, callable] = """ env = jinja2.Environment(loader=loader, undefined=self.undefined) - env["DOLLAR_CURLY_BRACE"} = TemplateConstants.DOLLAR_CURLY_BRACE - env["DOLLAR_PARENTHESES"} = TemplateConstants.DOLLAR_PARENTHESES - env["DOUBLE_CURLY_BRACES"} = TemplateConstants.DOUBLE_CURLY_BRACES - env["AT_SQUARE_BRACES"} = TemplateConstants.AT_SQUARE_BRACES - env["AT_ANGLE_BRACKETS"} = TemplateConstants.AT_ANGLE_BRACKETS + env.extend(DOLLAR_CURLY_BRACE=TemplateConstants.DOLLAR_CURLY_BRACE, + DOLLAR_PARENTHESES=TemplateConstants.DOLLAR_PARENTHESES, + DOUBLE_CURLY_BRACES=TemplateConstants.DOUBLE_CURLY_BRACES, + AT_SQUARE_BRACES=TemplateConstants.AT_SQUARE_BRACES, + AT_ANGLE_BRACKETS=TemplateConstants.AT_ANGLE_BRACKETS) env.filters["strftime"] = lambda dt, fmt: strftime(dt, fmt) env.filters["to_isotime"] = lambda dt: to_isotime(dt) if not isinstance(dt, SilentUndefined) else dt From 57afd64ffa7c055621d4fecd288c228918910225 Mon Sep 17 00:00:00 2001 From: DavidHuber Date: Wed, 1 May 2024 18:33:15 +0000 Subject: [PATCH 5/6] Add template constants to environment globals; add expression statement extension --- src/wxflow/jinja.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/wxflow/jinja.py b/src/wxflow/jinja.py index abbc264..3efbf37 100644 --- a/src/wxflow/jinja.py +++ b/src/wxflow/jinja.py @@ -6,7 +6,7 @@ import jinja2 from markupsafe import Markup -from .template import TemplateConstants +from .template import TemplateConstants, Template from .timetools import (add_to_datetime, strftime, to_fv3time, to_isotime, to_julian, to_timedelta, to_YMD, to_YMDH) @@ -114,6 +114,11 @@ def get_set_env(self, loader: jinja2.BaseLoader, filters: Dict[str, callable] = template_substitute_structure: traverses a dictionary and substitutes variables in fields, lists, and nested dictionaries + The Expression Statement extension "jinja2.ext.do", which enables + {% do ... %} statements. These are useful for appending to lists. + e.g. {{ bar.append(foo) }} would print "None" to the parsed jinja + template, but {% do bar.append(foo) %} would not. + Additionally, the following TemplateConstants are passed into the environment: DOLLAR_CURLY_BRACE @@ -135,11 +140,14 @@ def get_set_env(self, loader: jinja2.BaseLoader, filters: Dict[str, callable] = """ env = jinja2.Environment(loader=loader, undefined=self.undefined) - env.extend(DOLLAR_CURLY_BRACE=TemplateConstants.DOLLAR_CURLY_BRACE, - DOLLAR_PARENTHESES=TemplateConstants.DOLLAR_PARENTHESES, - DOUBLE_CURLY_BRACES=TemplateConstants.DOUBLE_CURLY_BRACES, - AT_SQUARE_BRACES=TemplateConstants.AT_SQUARE_BRACES, - AT_ANGLE_BRACKETS=TemplateConstants.AT_ANGLE_BRACKETS) + + env.globals["DOLLAR_CURLY_BRACE"] = TemplateConstants.DOLLAR_CURLY_BRACE + env.globals["DOLLAR_PARENTHESES"] = TemplateConstants.DOLLAR_PARENTHESES + env.globals["DOUBLE_CURLY_BRACES"] = TemplateConstants.DOUBLE_CURLY_BRACES + env.globals["AT_SQUARE_BRACES"] = TemplateConstants.AT_SQUARE_BRACES + env.globals["AT_ANGLE_BRACKETS"] = TemplateConstants.AT_ANGLE_BRACKETS + + env.add_extension("jinja2.ext.do") env.filters["strftime"] = lambda dt, fmt: strftime(dt, fmt) env.filters["to_isotime"] = lambda dt: to_isotime(dt) if not isinstance(dt, SilentUndefined) else dt @@ -163,7 +171,7 @@ def get_set_env(self, loader: jinja2.BaseLoader, filters: Dict[str, callable] = if not (isinstance(structure_to_substitute, SilentUndefined) or isinstance(var_type, SilentUndefined) or isinstance(get_value, SilentUndefined)) - else structure_to_substitute if isinstance(structure_to_substitute, SlilentUndefined) + else structure_to_substitute if isinstance(structure_to_substitute, SilentUndefined) else var_type if isinstance(var_type, SilentUndefined) else get_value) From 1873fee09ce11b77a584b1423e32c42589c53459 Mon Sep 17 00:00:00 2001 From: DavidHuber Date: Fri, 3 May 2024 14:11:06 +0000 Subject: [PATCH 6/6] Remove Template references for now --- src/wxflow/jinja.py | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/wxflow/jinja.py b/src/wxflow/jinja.py index 3efbf37..cffea62 100644 --- a/src/wxflow/jinja.py +++ b/src/wxflow/jinja.py @@ -6,7 +6,6 @@ import jinja2 from markupsafe import Markup -from .template import TemplateConstants, Template from .timetools import (add_to_datetime, strftime, to_fv3time, to_isotime, to_julian, to_timedelta, to_YMD, to_YMDH) @@ -111,22 +110,12 @@ def get_set_env(self, loader: jinja2.BaseLoader, filters: Dict[str, callable] = getenv: read variable from environment if defined, else UNDEFINED to_timedelta: convert a string to a timedelta object add_to_datetime: add time to a datetime, return new datetime object - template_substitute_structure: traverses a dictionary and substitutes - variables in fields, lists, and nested dictionaries The Expression Statement extension "jinja2.ext.do", which enables {% do ... %} statements. These are useful for appending to lists. e.g. {{ bar.append(foo) }} would print "None" to the parsed jinja template, but {% do bar.append(foo) %} would not. - Additionally, the following TemplateConstants are passed into the - environment: - DOLLAR_CURLY_BRACE - DOLLAR_PARENTHESES - DOUBLE_CURLY_BRACES - AT_SQUARE_BRACES - AT_ANGLE_BRACKETS - Parameters ---------- loader: jinja2.BaseLoader @@ -141,12 +130,6 @@ def get_set_env(self, loader: jinja2.BaseLoader, filters: Dict[str, callable] = env = jinja2.Environment(loader=loader, undefined=self.undefined) - env.globals["DOLLAR_CURLY_BRACE"] = TemplateConstants.DOLLAR_CURLY_BRACE - env.globals["DOLLAR_PARENTHESES"] = TemplateConstants.DOLLAR_PARENTHESES - env.globals["DOUBLE_CURLY_BRACES"] = TemplateConstants.DOUBLE_CURLY_BRACES - env.globals["AT_SQUARE_BRACES"] = TemplateConstants.AT_SQUARE_BRACES - env.globals["AT_ANGLE_BRACKETS"] = TemplateConstants.AT_ANGLE_BRACKETS - env.add_extension("jinja2.ext.do") env.filters["strftime"] = lambda dt, fmt: strftime(dt, fmt) @@ -163,17 +146,6 @@ def get_set_env(self, loader: jinja2.BaseLoader, filters: Dict[str, callable] = if not (isinstance(dt, SilentUndefined) or isinstance(delta, SilentUndefined)) else dt if isinstance(dt, SilentUndefined) else delta) env.filters["to_timedelta"] = lambda delta_str: to_timedelta(delta_str) if not isinstance(delta_str, SilentUndefined) else delta_str - env.filters["template_substitute_structure"] = ( - lambda structure_to_substitute, var_type, get_value: - Template.substitute_structure(structure_to_substitute, - var_type, - get_value) - if not (isinstance(structure_to_substitute, SilentUndefined) or - isinstance(var_type, SilentUndefined) or - isinstance(get_value, SilentUndefined)) - else structure_to_substitute if isinstance(structure_to_substitute, SilentUndefined) - else var_type if isinstance(var_type, SilentUndefined) - else get_value) # Add any additional filters if filters is not None: