def test_multiline_template(self): input = """{% def foo(): return "bar" bar = foo() %}{{bar}}""" expected = "bar" self.assertEqual(render(input, self.namespace), expected)
def _exec_list(exprs, namespace): log = logging.getLogger(__name__) for expr in exprs: _expr = render(expr, namespace) if os.path.isfile(_expr): log.debug("{} is a file, executing...".format(_expr)) namespace.update(runpy.run_path(_expr, init_globals=namespace)) else: log.debug("Executing {}".format(_expr)) exec(_expr, namespace)
def render_directory(src, dst, recursive, namespace): log = logging.getLogger(__name__) src = Path(render(src, namespace)) dst = Path(render(dst, namespace)) for root, dirs, filenames in os.walk(str(src), topdown=True): log.debug("In directory: {}".format(root)) for filename in filenames: filename = Path(os.path.join(root, filename)) log.debug("Found file {}".format(filename)) _dst = os.path.join(str(dst), os.path.relpath(str(filename), str(src))) render_file(filename, _dst, namespace) if recursive: for dirname in dirs: new_dir = Path(dst / dirname) log.debug("Recursive, rendering to {}".format(new_dir)) new_dir.mkdir(parents=True, exist_ok=True) else: log.debug("Not recursive, exiting") dirs.clear()
def render_file(src, dst, namespace): log = logging.getLogger(__name__) dst = Path(dst) src = Path(src) if src not in mtimes or src.stat().st_mtime != mtimes[src]: log.warn("Rendering {} -> {}".format(src, dst)) try: dst.write_text(render(src.read_text(), namespace)) finally: mtimes[src] = src.stat().st_mtime else: log.debug("File {} has not changed, skipping".format(src)) pass
def stream( filenames, add_paths, templates, begins, begin_lines, begin_files, end_files, tests, end_lines, ends, field_sep, namespaces, recursive, with_filenames, logging_config, logging_level, logging_format, suppress_tracebacks, add_env, ): """Pass streams of data through a processing/templating pipeline""" if logging_config: with open(logging_config, "r") as fp: logging.config.dictConfig(eval(fp.read())) else: logging.basicConfig( stream=sys.stdout, level=logging_level, format=logging_format, ) log = logging.getLogger(__name__) if add_paths is None: add_paths = [] for path in add_paths: if os.path.exists(path): sys.path.insert(0, path) else: log.critical("{} not found, invalid path".format(path)) sys.exit(-2) namespace = make_namespace({}, namespaces, add_env) if not filenames: log.debug("No filenames specified, defaulting to stdin") filenames = ["-"] _filenames = [] for filename in filenames: if filename == "-": _filenames.append("-") else: _filenames.extend(glob(filename, recursive=recursive)) filenames = list(filter(lambda x: not os.path.isdir(x), _filenames)) log.debug("Reading filenames {}".format(filenames)) last_filename = None nr = 0 if tests is None: tests = ["True"] if begins is None: begins = [] if begin_lines is None: begin_lines = [] if begin_files is None: begin_files = [] if end_files is None: end_files = [] if end_lines is None: end_lines = [] if ends is None: ends = [] _exec_list(begins, namespace) for filename in filenames: try: with click.open_file(filename, "rb") as fin: log.debug("Reading {}".format(filename)) for line in fin: log.debug("Got line: {}".format(line)) if filename != last_filename: if with_filenames: print("===> {} <===".format( os.path.abspath(filename))) namespace.update( {"filename": os.path.abspath(filename)}) fnr = 0 _exec_list(begin_files, namespace) last_filename = filename fnr, nr = fnr + 1, nr + 1 fields = line.split(field_sep) namespace.update({ "line": line.decode(), "filename": os.path.abspath(filename), "fields": fields, "nf": len(fields), "nr": nr, "fnr": fnr, }) if all( eval(render(test, namespace), namespace) for test in tests): _exec_list(begin_lines, namespace) for template in templates: log.debug( "Rendering template: {}".format(template)) try: results = render(template, namespace).strip() except: if not suppress_tracebacks: log.exception( "An unhandled exception occurred") continue log.debug("Result: {}".format(results)) if results: log.info(results) _exec_list(end_lines, namespace) _exec_list(end_files, namespace) except: if not suppress_tracebacks: log.exception("An unhandled exception occurred") continue _exec_list(ends, namespace) return 0
def test_expression_replaced_with_stdout(self): input = "{%print('hello, world')%}" expected = "hello, world\n" self.assertEqual(render(input, self.namespace), expected)
def test_multiline_substitution(self): input = """{{ str(["foo", "bar", "baz"]) }}""" expected = "['foo', 'bar', 'baz']" self.assertEqual(render(input, self.namespace), expected)
def test_simple_exec_import(self): input = "{% import string %}{{string.ascii_letters}}" expected_in = "abcdefghijklmnopqrstuvwxyz" self.assertIn(expected_in, render(input, self.namespace))
def test_simple_exec(self): input = "{% x = 5 %}{{str(x)}}" expected = "5" self.assertEqual(render(input, self.namespace), expected) self.assertEqual(self.namespace["x"], 5)
def test_namespace_substitution_with_function_call(self): input = "{{str(x)}}" expected = "42" self.assertEqual(render(input, self.namespace), expected)
def test_namespace_simple_substitution(self): input = "{{y}}" expected = "foo" self.assertEqual(render(input, self.namespace), expected)
def test_simple_substitution(self): """Test simple substitution.""" input = "{{'5'}}" expected = "5" self.assertEqual(render(input), expected)