From bcf938f6e8abfeb0ee39a920bf147c9240ea3e4a Mon Sep 17 00:00:00 2001
From: Adar Nimrod <nimrod@shore.co.il>
Date: Mon, 22 Jul 2019 12:07:02 +0300
Subject: [PATCH] Add run filter for running command and capturing their
 output.

---
 .travis.yml          |  1 -
 Pipfile.lock         | 63 ++++++++++++++------------------------------
 README.rst           |  5 +++-
 setup.py             |  9 +++++--
 template/__init__.py |  0
 template/filters.py  | 23 ++++++++++++++++
 6 files changed, 54 insertions(+), 47 deletions(-)
 mode change 100755 => 100644 template/__init__.py

diff --git a/.travis.yml b/.travis.yml
index 359681d..78897da 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,7 +3,6 @@
 language: python
 python:
   - "2.7"
-  - "3.4"
   - "3.5"
   - "3.6"
   - "3.7"
diff --git a/Pipfile.lock b/Pipfile.lock
index 144a03d..be17798 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "62827577f8781dd89462ca09eb23122a71010f2f121432f74817d72b1fad6bac"
+            "sha256": "c5874f74427fb4c93b0b946d55db06144a048e54bf913867cd0a76d8167f8412"
         },
         "pipfile-spec": 6,
         "requires": {
@@ -88,10 +88,10 @@
         },
         "cfgv": {
             "hashes": [
-                "sha256:32edbe09de6f4521224b87822103a8c16a614d31a894735f7a5b3bcf0eb3c37e",
-                "sha256:3bd31385cd2bebddbba8012200aaf15aa208539f1b33973759b4d02fc2148da5"
+                "sha256:edb387943b665bf9c434f717bf630fa78aecd53d5900d2e05da6ad6048553144",
+                "sha256:fbd93c9ab0a523bf7daec408f3be2ed99a980e20b2d19b50fc184ca6b820d289"
             ],
-            "version": "==2.0.0"
+            "version": "==2.0.1"
         },
         "chardet": {
             "hashes": [
@@ -130,11 +130,10 @@
         },
         "docutils": {
             "hashes": [
-                "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
-                "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274",
-                "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6"
+                "sha256:54a349c622ff31c91cbec43b0b512f113b5b24daf00e2ea530bb1bd9aac14849",
+                "sha256:d2ddba74835cb090a1b627d3de4e7835c628d07ee461f7b4480f51af2fe4d448"
             ],
-            "version": "==0.14"
+            "version": "==0.15"
         },
         "entrypoints": {
             "hashes": [
@@ -143,14 +142,6 @@
             ],
             "version": "==0.3"
         },
-        "hashin": {
-            "hashes": [
-                "sha256:dbace6900d8de44f3106a64496803e45843cf4974755613db811a487fadbf4c6",
-                "sha256:fe764df71cabbbddfa72aa4d6685581c932bb5cf9100ddee6b2b04f3446ae2f7"
-            ],
-            "index": "pypi",
-            "version": "==0.14.5"
-        },
         "identify": {
             "hashes": [
                 "sha256:0a11379b46d06529795442742a043dc2fa14cd8c995ae81d1febbc5f1c014c87",
@@ -240,20 +231,6 @@
             ],
             "version": "==1.3.3"
         },
-        "packaging": {
-            "hashes": [
-                "sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af",
-                "sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3"
-            ],
-            "version": "==19.0"
-        },
-        "pip-api": {
-            "hashes": [
-                "sha256:742b3edb5b077853ffcfec8a849f6ff1a622c6ecf648adb5fa0e4594998fcd46",
-                "sha256:a685eb315b9f10f6df4ceb66f3710148c8ad7de2d4ff29ee98fed0e4d949ec81"
-            ],
-            "version": "==0.0.10"
-        },
         "pkginfo": {
             "hashes": [
                 "sha256:7424f2c8511c186cd5424bbf31045b77435b37a8d604990b79d4e70d741148bb",
@@ -282,13 +259,6 @@
             ],
             "version": "==2.4.2"
         },
-        "pyparsing": {
-            "hashes": [
-                "sha256:1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a",
-                "sha256:9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03"
-            ],
-            "version": "==2.4.0"
-        },
         "pyyaml": {
             "hashes": [
                 "sha256:57acc1d8533cbe51f6662a55434f0dbecfa2b9eaf115bede8f6fd00115a0c0d3",
@@ -341,6 +311,13 @@
             ],
             "version": "==1.12.0"
         },
+        "subprocess32": {
+            "hashes": [
+                "sha256:88e37c1aac5388df41cc8a8456bb49ebffd321a3ad4d70358e3518176de3a56b",
+                "sha256:eb2937c80497978d181efa1b839ec2d9622cf9600a039a79d0e108d1f9aec79d"
+            ],
+            "version": "==3.5.4"
+        },
         "template": {
             "editable": true,
             "path": "."
@@ -376,10 +353,10 @@
         },
         "virtualenv": {
             "hashes": [
-                "sha256:b7335cddd9260a3dd214b73a2521ffc09647bde3e9457fcca31dc3be3999d04a",
-                "sha256:d28ca64c0f3f125f59cabf13e0a150e1c68e5eea60983cc4395d88c584495783"
+                "sha256:861bbce3a418110346c70f5c7a696fdcf23a261424e1d28aa4f9362fc2ccbc19",
+                "sha256:ba8ce6a961d842320681fb90a3d564d0e5134f41dacd0e2bae7f02441dde2d52"
             ],
-            "version": "==16.6.1"
+            "version": "==16.6.2"
         },
         "webencodings": {
             "hashes": [
@@ -390,10 +367,10 @@
         },
         "zipp": {
             "hashes": [
-                "sha256:8c1019c6aad13642199fbe458275ad6a84907634cc9f0989877ccc4a2840139d",
-                "sha256:ca943a7e809cc12257001ccfb99e3563da9af99d52f261725e96dfe0f9275bc3"
+                "sha256:4970c3758f4e89a7857a973b1e2a5d75bcdc47794442f2e2dd4fe8e0466e809a",
+                "sha256:8a5712cfd3bb4248015eb3b0b3c54a5f6ee3f2425963ef2a0125b8bc40aafaec"
             ],
-            "version": "==0.5.1"
+            "version": "==0.5.2"
         }
     }
 }
diff --git a/README.rst b/README.rst
index da23155..dfe8dd4 100644
--- a/README.rst
+++ b/README.rst
@@ -5,7 +5,7 @@ Template
     :target: https://travis-ci.org/adarnimrod/template
 
 A CLI tool for generating files from `Jinja2 <http://jinja.pocoo.org/>`_
-templates and environment variables. Tested on Python versions 2.7, 3.4 and
+templates and environment variables. Tested on Python versions 2.7, 3.5 and
 later.
 
 Examples
@@ -48,6 +48,9 @@ The following Jinja filters were added:
 - :code:`from_toml`: Convert from toml.
 - :code:`jmespath`: Queries data using the `JMESPath <http://jmespath.org/>`_
   query language.
+- :code:`run`: 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>`_.
 
 Example usage can be seen in :code:`tests` and for specific filters in the
 docstrings in :code:`template/filters.py`.
diff --git a/setup.py b/setup.py
index 5d3d4dc..903465d 100644
--- a/setup.py
+++ b/setup.py
@@ -17,7 +17,6 @@ setup(
         "Development Status :: 4 - Beta",
         "Intended Audience :: Developers",
         "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.4",
         "Programming Language :: Python :: 3.5",
         "Programming Language :: Python :: 3.6",
         "Programming Language :: Python :: 3.7",
@@ -29,7 +28,13 @@ setup(
     ],
     keywords="config configuration jinja template environment",
     packages=find_packages(),
-    install_requires=["Jinja2", "PyYAML", "jmespath", "toml"],
+    install_requires=[
+        "Jinja2",
+        "PyYAML",
+        "jmespath",
+        "toml",
+        "subprocess32>=3.5.0",
+    ],
     extras_require={"dev": ["pipenv"]},
     entry_points={"console_scripts": ["template=template:main"]},
 )
diff --git a/template/__init__.py b/template/__init__.py
old mode 100755
new mode 100644
diff --git a/template/filters.py b/template/filters.py
index f17598f..6d1a9f5 100644
--- a/template/filters.py
+++ b/template/filters.py
@@ -143,3 +143,26 @@ def jmespath(value, query):
     import jmespath as jp
 
     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 subprocess32  # nosec
+
+    defaults = {"stdout": subprocess32.PIPE, "stderr": subprocess32.PIPE}
+    defaults.update(kwargs)
+    proc = subprocess32.run(*argv, **defaults).__dict__
+    if "text" not in kwargs or kwargs["text"]:
+        proc["stdout"] = proc["stdout"].decode()
+        proc["stderr"] = proc["stderr"].decode()
+    return proc
-- 
GitLab