diff --git a/README.rst b/README.rst index d60fbe0f7b0957cf4c1c836ef1f1e4ffac7eda2b..40472bb92e943670273462e1a26754c2b3510a77 100644 --- a/README.rst +++ b/README.rst @@ -81,6 +81,8 @@ Jinja filters The following Jinja filters were added: +- :code:`combine`: Merges 2 dictionaries with the 2nd overriding the 1st. + Returns the result. - :code:`to_yaml`: Convert to yaml (requires the :code:`yaml` package specifier). - :code:`from_yaml`: Convert from yaml (requires the :code:`yaml` package @@ -94,8 +96,8 @@ The following Jinja filters were added: - :code:`jmespath`: Queries data using the `JMESPath <http://jmespath.org/>`_ query language (requires the :code:`jmespath` package specifier). - :code:`run`: Runs a command and returns the stdout, stderr and returncode - using `run - <https://docs.python.org/3.6/library/subprocess.html?highlight=popen#subprocess.run>`_. + using run_. This filter is replaced with the :code:`run` function and will + be removed in the 0.10 release. - :code:`ipaddress`: Returns an IPAddress object from the netaddr_ library (requires the :code:`netaddr` package specifier). - :code:`ipnetwork`: Returns an IPNetwork object from the netaddr_ library @@ -104,10 +106,21 @@ The following Jinja filters were added: (requires the :code:`netaddr` package specifier). - :code:`ipglob`: Returns an IPGlob object from the netaddr_ library (requires the :code:`netaddr` package specifier). +- :code:`ipset`: Returns an IPSet object from the netaddr_ library (requires + the :code:`netaddr` package specifier). Example usage can be seen in :code:`tests` and for specific filters in the docstrings in :code:`template/filters.py`. +Jinja functions +--------------- + +- :code:`run`: Runs a command and returns the stdout, stderr and returncode + using run_. This function replaces the :code:`run` filter. + +Example usage can be seen in :code:`tests` and for specific filters in the +docstrings in :code:`template/functions.py`. + Testing ------- @@ -152,3 +165,4 @@ at: https://git.shore.co.il/nimrod/. .. _netaddr: https://netaddr.readthedocs.io/ .. _Pipenv: https://docs.pipenv.org +.. _run: https://docs.python.org/3.6/library/subprocess.html?highlight=popen#subprocess.run diff --git a/template/__init__.py b/template/__init__.py index c218023718a892bdd8138e2a74202c23df32fedc..fee78d16ae1f123e35dda44394e50f2e4c9609a0 100644 --- a/template/__init__.py +++ b/template/__init__.py @@ -13,6 +13,7 @@ from os import environ import sys import argparse import template.filters +import template.functions # I ignore import errors here and fail on them later in the main function so # the module can be imported by the setup.py with jinja missing so the @@ -31,9 +32,18 @@ def render(template_string): env = Environment(autoescape=True) # Add all functions in template.filters as Jinja filters. # pylint: disable=invalid-name - for tf in filter(lambda x: not x.startswith("_"), dir(template.filters)): + for tf in filter( + lambda x: callable(getattr(template.filters, x)) + and not x.startswith("_"), + dir(template.filters), + ): env.filters[tf] = getattr(template.filters, tf) - t = env.from_string(template_string) + functions = { + x: getattr(template.functions, x) + for x in dir(template.functions) + if callable(getattr(template.functions, x)) and not x.startswith("_") + } + t = env.from_string(template_string, globals=functions) return t.render(environ) diff --git a/template/filters.py b/template/filters.py index 085cf6fec5188e44b6074c83593fb56f02116134..4fb8c8b01ec182519af10ce0e290a749c1c1fe0d 100644 --- a/template/filters.py +++ b/template/filters.py @@ -10,6 +10,8 @@ from __future__ import ( unicode_literals, ) # pylint: disable=duplicate-code +from template.functions import run # noqa: F401 pylint: disable=unused-import + def to_yaml(value): r""" @@ -145,36 +147,6 @@ def jmespath(value, query): return jp.search(query, value) -def run(*argv, **kwargs): - """ - Runs a command and returns the stdout, stderr and returncode - using `run - <https://docs.python.org/3.5/library/subprocess.html?highlight=popen#subprocess.run>`_. - >>> run('ls')["returncode"] == 0 - True - >>> 'SHELL' not in run('echo $SHELL', shell=True)['stdout'] - True - >>> run(['ls', 'foo'])['returncode'] > 0 - True - """ - import sys - - if sys.version_info[0] < 3: # nosec - import subprocess32 as subprocess - else: - import subprocess # nosemgrep: rules.bandit.B40 - - defaults = {"stdout": subprocess.PIPE, "stderr": subprocess.PIPE} - defaults.update(kwargs) - proc = subprocess.run( # nosec, pylint: disable=subprocess-run-check - *argv, **defaults - ).__dict__ - if "text" not in kwargs or kwargs["text"]: - proc["stdout"] = proc["stdout"].decode() - proc["stderr"] = proc["stderr"].decode() - return proc - - def ipaddress(addr, version=None, flags=0): """ Returns an IPAddress object from the netaddr library. diff --git a/template/functions.py b/template/functions.py new file mode 100644 index 0000000000000000000000000000000000000000..c219b2e1e9258211a6915dbb796963b259d508fe --- /dev/null +++ b/template/functions.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +"""Filters for the template CLI.""" +# pylint: disable=import-error, import-outside-toplevel + + +from __future__ import ( + absolute_import, + division, + print_function, + unicode_literals, +) # pylint: disable=duplicate-code + + +def run(*argv, **kwargs): + """ + Runs a command and returns the stdout, stderr and returncode + using `run + <https://docs.python.org/3.5/library/subprocess.html?highlight=popen#subprocess.run>`_. + >>> run('ls')["returncode"] == 0 + True + >>> 'SHELL' not in run('echo $SHELL', shell=True)['stdout'] + True + >>> run(['ls', 'foo'])['returncode'] > 0 + True + """ + import sys + + if sys.version_info[0] < 3: # nosec + import subprocess32 as subprocess + else: + import subprocess # nosemgrep: rules.bandit.B40 + + defaults = {"stdout": subprocess.PIPE, "stderr": subprocess.PIPE} + defaults.update(kwargs) + proc = subprocess.run( # nosec, pylint: disable=subprocess-run-check + *argv, **defaults + ).__dict__ + if "text" not in kwargs or kwargs["text"]: + proc["stdout"] = proc["stdout"].decode() + proc["stderr"] = proc["stderr"].decode() + return proc