def eval_macro(self, token: Token, macros: MacroList, trace: list) -> Tuple[Token, bool]: # Get macro definition if '__macro' in token: name = token.pop('__macro') macro, extend = self.macro_definitions[name], False elif '__macro!' in token: name = token.pop('__macro!') macro, extend = self.macro_definitions[name], True else: raise Exception('Illegal state') new_trace = trace + [name + "(template)"] # Validate input against the schema if 'schema' in macro: try: validate(token, macro['schema']) except ValidationError as err: log.error( "%s: schema validation error on input to macro %s: %s", format_trace(trace), name, repr(err)) raise err # Replace '%' in template with key template = json.loads( json.dumps(macro['template']).replace("%", str(trace[-1]))) # Populate template from input (i.e. the token) subs_macros = [JqSubstitutionMacro(token)] result = traverse(template, subs_macros, new_trace)[0] return traverse(result, macros, new_trace)[0], extend
def test_class_macro_in_place_array(): obj = { "foo": [1, {"__macro": "foobar"}, 3] } foo, extend = traverse(obj, macros, []) assert foo == { "foo": [1, {"a": "b"}, 3] }
def test_class_macro_in_place(): obj = { "foo": {"__macro": "foobar"} } foo, extend = traverse(obj, macros, []) assert foo == { "foo": {"a": "b"} }
def test_class_recursive_macro(): obj = { "foo": {"__macro": "foorecurse"} } foo, extend = traverse(obj, macros, []) assert foo == { "foo": { "foo": {"a": "b"} } }
def test_class_order_preserved(): obj = { "foo": {"__macro": "foobar"}, "baz": {"__macro!": "foobar"}, "bar": {"__macro": "foobar"} } exp = { "foo": {"a": "b"}, "a": "b", "bar": {"a": "b"} } result = traverse(obj, macros, [])[0] assert len(exp) == len(result) for k1, k2 in zip(exp, result): assert k1 == k2
def eval_macro(self, token: Token, macros: MacroList, trace: list) -> Tuple[Token, bool]: if isinstance(token, dict): expression = token.pop('__jq') new_token = jq_select(expression, self.data) return traverse(new_token, macros, trace + [f"<{expression}>"]) else: # str while match := self.SUB_REGEX.search(token): new_token = jq_select(match.group(1)[2:-1], self.data) new_str = json.dumps(new_token) if isinstance( new_token, dict) or isinstance(new_token, list) else str(new_token) token = token.replace(match.group(1), new_str) log.debug(f"After replacement: {token}") return token, False
def test_traverse(): obj = {"foo": "bar", "baz": [1, 2, 3], "quux": {"a": "b"}} foo, extend = traverse(obj, {}, []) assert obj == foo
def test_class_macro_extend_array(): obj = [1, {"__macro!": "foolist"}, 3] foo, extend = traverse(obj, macros, []) assert foo == [1, 1, 2, 3, 3]
def traverse_and_compare(obj: Token, exp: Token, macros: MacroList): result, expand = traverse(obj, macros, []) logging.debug(f"Result: {result}") logging.debug(f"Expect: {exp}") assert result == exp