Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

json-e

Package Overview
Dependencies
Maintainers
4
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

json-e - npm Package Compare versions

Comparing version
4.5.3
to
4.6.0
+1
-1
json_e.egg-info/PKG-INFO
Metadata-Version: 2.1
Name: json-e
Version: 4.5.3
Version: 4.6.0
Summary: A data-structure parameterization system written for embedding context in JSON objects

@@ -5,0 +5,0 @@ Home-page: https://json-e.js.org

@@ -8,3 +8,3 @@ from __future__ import absolute_import, print_function, unicode_literals

_context_re = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*$')
_context_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")

@@ -16,5 +16,6 @@

if not all(_context_re.match(c) for c in context):
raise TemplateError('top level keys of context must follow '
'/[a-zA-Z_][a-zA-Z0-9_]*/')
full_context = {'now': fromNow('0 seconds', None)}
raise TemplateError(
"top level keys of context must follow " "/[a-zA-Z_][a-zA-Z0-9_]*/"
)
full_context = {"now": fromNow("0 seconds", None)}
full_context.update(builtins.build())

@@ -26,3 +27,3 @@ full_context.update(context)

if containsFunctions(rv):
raise TemplateError('evaluated template contained uncalled functions')
raise TemplateError("evaluated template contained uncalled functions")
return rv

@@ -14,5 +14,8 @@ from __future__ import absolute_import, print_function, unicode_literals

def builtin(name, variadic=None, argument_tests=None, minArgs=None, needs_context=False):
def builtin(
name, variadic=None, argument_tests=None, minArgs=None, needs_context=False
):
def wrap(fn):
if variadic:
def invoke(context, *args):

@@ -22,7 +25,11 @@ if minArgs:

raise BuiltinError(
'invalid arguments to builtin: {}: expected at least {} arguments'.format(name, minArgs)
"invalid arguments to builtin: {}: expected at least {} arguments".format(
name, minArgs
)
)
for arg in args:
if not variadic(arg):
raise BuiltinError('invalid arguments to builtin: {}'.format(name))
raise BuiltinError(
"invalid arguments to builtin: {}".format(name)
)
if needs_context is True:

@@ -33,8 +40,13 @@ return fn(context, *args)

elif argument_tests:
def invoke(context, *args):
if len(args) != len(argument_tests):
raise BuiltinError('invalid arguments to builtin: {}'.format(name))
raise BuiltinError(
"invalid arguments to builtin: {}".format(name)
)
for t, arg in zip(argument_tests, args):
if not t(arg):
raise BuiltinError('invalid arguments to builtin: {}'.format(name))
raise BuiltinError(
"invalid arguments to builtin: {}".format(name)
)
if needs_context is True:

@@ -45,2 +57,3 @@ return fn(context, *args)

else:
def invoke(context, *args):

@@ -76,44 +89,46 @@ if needs_context is True:

def anything(v):
return isinstance(v, (string, int, float, list, dict)) or v is None or callable(v)
return (
isinstance(v, (string, int, float, list, dict)) or v is None or callable(v)
)
# ---
builtin('min', variadic=is_number, minArgs=1)(min)
builtin('max', variadic=is_number, minArgs=1)(max)
builtin('sqrt', argument_tests=[is_number])(math.sqrt)
builtin('abs', argument_tests=[is_number])(abs)
builtin("min", variadic=is_number, minArgs=1)(min)
builtin("max", variadic=is_number, minArgs=1)(max)
builtin("sqrt", argument_tests=[is_number])(math.sqrt)
builtin("abs", argument_tests=[is_number])(abs)
@builtin('ceil', argument_tests=[is_number])
@builtin("ceil", argument_tests=[is_number])
def ceil(v):
return int(math.ceil(v))
@builtin('floor', argument_tests=[is_number])
@builtin("floor", argument_tests=[is_number])
def floor(v):
return int(math.floor(v))
@builtin('lowercase', argument_tests=[is_string])
@builtin("lowercase", argument_tests=[is_string])
def lowercase(v):
return v.lower()
@builtin('uppercase', argument_tests=[is_string])
@builtin("uppercase", argument_tests=[is_string])
def lowercase(v):
return v.upper()
builtin('len', argument_tests=[is_string_or_array])(len)
builtin('str', argument_tests=[anything_except_array])(to_str)
builtin('number', variadic=is_string, minArgs=1)(float)
builtin("len", argument_tests=[is_string_or_array])(len)
builtin("str", argument_tests=[anything_except_array])(to_str)
builtin("number", variadic=is_string, minArgs=1)(float)
@builtin('strip', argument_tests=[is_string])
@builtin("strip", argument_tests=[is_string])
def strip(s):
return s.strip()
@builtin('rstrip', argument_tests=[is_string])
@builtin("rstrip", argument_tests=[is_string])
def rstrip(s):
return s.rstrip()
@builtin('lstrip', argument_tests=[is_string])
@builtin("lstrip", argument_tests=[is_string])
def lstrip(s):
return s.lstrip()
@builtin('join', argument_tests=[is_array, is_string_or_number])
@builtin("join", argument_tests=[is_array, is_string_or_number])
def join(list, separator):

@@ -125,4 +140,4 @@ # convert potential numbers into strings

@builtin('split', variadic=is_string_or_number, minArgs=1)
def split(s, d=''):
@builtin("split", variadic=is_string_or_number, minArgs=1)
def split(s, d=""):
if not d and is_string(s):

@@ -133,24 +148,24 @@ return list(s)

@builtin('fromNow', variadic=is_string, minArgs=1, needs_context=True)
@builtin("fromNow", variadic=is_string, minArgs=1, needs_context=True)
def fromNow_builtin(context, offset, reference=None):
return fromNow(offset, reference or context.get('now'))
return fromNow(offset, reference or context.get("now"))
@builtin('typeof', argument_tests=[anything])
@builtin("typeof", argument_tests=[anything])
def typeof(v):
if isinstance(v, bool):
return 'boolean'
return "boolean"
elif isinstance(v, string):
return 'string'
return "string"
elif isinstance(v, (int, float)):
return 'number'
return "number"
elif isinstance(v, list):
return 'array'
return "array"
elif isinstance(v, dict):
return 'object'
return "object"
elif v is None:
return 'null'
return "null"
elif callable(v):
return 'function'
return "function"
@builtin('defined', argument_tests=[is_string], needs_context=True)
@builtin("defined", argument_tests=[is_string], needs_context=True)
def defined(context, s):

@@ -157,0 +172,0 @@ if s not in context:

@@ -6,4 +6,5 @@ from .shared import InterpreterError, string

def infixExpectationError(operator, expected):
return InterpreterError('infix: {} expects {} {} {}'.
format(operator, expected, operator, expected))
return InterpreterError(
"infix: {} expects {} {} {}".format(operator, expected, operator, expected)
)

@@ -16,3 +17,3 @@

def visit(self, node):
method_name = 'visit_' + type(node).__name__
method_name = "visit_" + type(node).__name__
visitor = getattr(self, method_name)

@@ -24,3 +25,3 @@ return visitor(node)

v = node.token.value
return float(v) if '.' in v else int(v)
return float(v) if "." in v else int(v)
elif node.token.kind == "null":

@@ -41,7 +42,7 @@ return None

if not is_number(value):
raise InterpreterError('{} expects {}'.format('unary +', 'number'))
raise InterpreterError("{} expects {}".format("unary +", "number"))
return value
elif node.token.kind == "-":
if not is_number(value):
raise InterpreterError('{} expects {}'.format('unary -', 'number'))
raise InterpreterError("{} expects {}".format("unary -", "number"))
return -value

@@ -62,8 +63,9 @@ elif node.token.kind == "!":

if not isinstance(left, (string, int, float)) or isinstance(left, bool):
raise infixExpectationError('+', 'numbers/strings')
raise infixExpectationError("+", "numbers/strings")
if not isinstance(right, (string, int, float)) or isinstance(right, bool):
raise infixExpectationError('+', 'numbers/strings')
if type(right) != type(left) and \
(isinstance(left, string) or isinstance(right, string)):
raise infixExpectationError('+', 'numbers/strings')
raise infixExpectationError("+", "numbers/strings")
if type(right) != type(left) and (
isinstance(left, string) or isinstance(right, string)
):
raise infixExpectationError("+", "numbers/strings")
return left + right

@@ -97,26 +99,26 @@ elif node.token.kind == "-":

test_math_operands("**", left, right)
return right ** left
return right**left
elif node.token.value == "in":
if isinstance(right, dict):
if not isinstance(left, string):
raise infixExpectationError('in-object', 'string on left side')
raise infixExpectationError("in-object", "string on left side")
elif isinstance(right, string):
if not isinstance(left, string):
raise infixExpectationError('in-string', 'string on left side')
raise infixExpectationError("in-string", "string on left side")
elif not isinstance(right, list):
raise infixExpectationError(
'in', 'Array, string, or object on right side')
"in", "Array, string, or object on right side"
)
try:
return left in right
except TypeError:
raise infixExpectationError('in', 'scalar value, collection')
raise infixExpectationError("in", "scalar value, collection")
elif node.token.kind == ".":
if not isinstance(left, dict):
raise InterpreterError('infix: {} expects {}'.format(".", 'objects'))
raise InterpreterError("infix: {} expects {}".format(".", "objects"))
try:
return left[right]
except KeyError:
raise InterpreterError(
'object has no property "{}"'.format(right))
raise InterpreterError('object has no property "{}"'.format(right))

@@ -149,3 +151,5 @@ def visit_List(self, node):

except TypeError:
raise InterpreterError('cannot perform interval access with non-integers')
raise InterpreterError(
"cannot perform interval access with non-integers"
)
else:

@@ -155,10 +159,14 @@ try:

except IndexError:
raise InterpreterError('index out of bounds')
raise InterpreterError("index out of bounds")
except TypeError:
raise InterpreterError('should only use integers to access arrays or strings')
raise InterpreterError(
"should only use integers to access arrays or strings"
)
if not isinstance(value, dict):
raise InterpreterError('infix: {} expects {}'.format('"[..]"', 'object, array, or string'))
raise InterpreterError(
"infix: {} expects {}".format('"[..]"', "object, array, or string")
)
if not isinstance(left, string):
raise InterpreterError('object keys must be strings')
raise InterpreterError("object keys must be strings")

@@ -174,4 +182,3 @@ try:

except KeyError:
raise InterpreterError(
'unknown context value {}'.format(node.token.value))
raise InterpreterError("unknown context value {}".format(node.token.value))
return contextValue

@@ -191,4 +198,3 @@

else:
raise InterpreterError(
'{} is not callable'.format(func_name))
raise InterpreterError("{} is not callable".format(func_name))

@@ -207,5 +213,5 @@ def visit_Object(self, node):

if not is_number(left):
raise infixExpectationError(op, 'number')
raise infixExpectationError(op, "number")
if not is_number(right):
raise infixExpectationError(op, 'number')
raise infixExpectationError(op, "number")
return

@@ -215,5 +221,6 @@

def test_comparison_operands(op, left, right):
if type(left) != type(right) or \
not (isinstance(left, (int, float, string)) and not isinstance(left, bool)):
raise infixExpectationError(op, 'numbers/strings')
if type(left) != type(right) or not (
isinstance(left, (int, float, string)) and not isinstance(left, bool)
):
raise infixExpectationError(op, "numbers/strings")
return

@@ -220,0 +227,0 @@

@@ -1,2 +0,11 @@

from .AST import Primitive, UnaryOp, ContextValue, BinOp, FunctionCall, ValueAccess, Object, List
from .AST import (
Primitive,
UnaryOp,
ContextValue,
BinOp,
FunctionCall,
ValueAccess,
Object,
List,
)
from collections import namedtuple

@@ -6,13 +15,25 @@ import re

Token = namedtuple('Token', ['kind', 'value', 'start', 'end'])
Token = namedtuple("Token", ["kind", "value", "start", "end"])
expectedTokens = ["!", "(", "+", "-", "[", "false", "identifier", "null", "number", "string", "true", "{"]
expectedTokens = [
"!",
"(",
"+",
"-",
"[",
"false",
"identifier",
"null",
"number",
"string",
"true",
"{",
]
class SyntaxError(TemplateError):
@classmethod
def unexpected(cls, got, exp):
exp = ', '.join(sorted(exp))
return cls('Found: {} token, expected one of: {}'.format(got.value, exp))
exp = ", ".join(sorted(exp))
return cls("Found: {} token, expected one of: {}".format(got.value, exp))

@@ -27,8 +48,16 @@

self.primitivesTokens = ["number", "null", "true", "false", "string"]
self.operatorsByPriority = [["||"], ["&&"], ["in"], ["==", "!="], ["<", ">", "<=", ">="], ["+", "-"],
["*", "/"], ["**"]]
self.operatorsByPriority = [
["||"],
["&&"],
["in"],
["==", "!="],
["<", ">", "<=", ">="],
["+", "-"],
["*", "/"],
["**"],
]
def take_token(self, *kinds):
if not self.current_token:
raise SyntaxError('Unexpected end of input')
raise SyntaxError("Unexpected end of input")
if kinds and self.current_token.kind not in kinds:

@@ -44,3 +73,3 @@ raise SyntaxError.unexpected(self.current_token, kinds)

def parse(self, level=0):
""" expr : logicalAnd (OR logicalAnd)* """
"""expr : logicalAnd (OR logicalAnd)*"""
""" logicalAnd : inStatement (AND inStatement)* """

@@ -73,3 +102,3 @@ """ inStatement : equality (IN equality)* """

def parse_property_access_or_func(self):
""" propertyAccessOrFunc : unit (accessWithBrackets | DOT id | functionCall)* """
"""propertyAccessOrFunc : unit (accessWithBrackets | DOT id | functionCall)*"""
node = self.parse_unit()

@@ -96,3 +125,3 @@ token = self.current_token

if self.current_token is None:
raise SyntaxError('Unexpected end of input')
raise SyntaxError("Unexpected end of input")
node = None

@@ -145,3 +174,3 @@

def parse_list(self):
""" list: LSQAREBRAKET (expr (COMMA expr)*)? RSQAREBRAKET """
"""list: LSQAREBRAKET (expr (COMMA expr)*)? RSQAREBRAKET"""
arr = []

@@ -168,3 +197,3 @@ token = self.current_token

def parse_access_with_brackets(self, node):
""" valueAccess : LSQAREBRAKET expr |(expr? COLON expr?) RSQAREBRAKET)"""
"""valueAccess : LSQAREBRAKET expr |(expr? COLON expr?) RSQAREBRAKET)"""
left = None

@@ -201,3 +230,5 @@ right = None

while token is not None and (token.kind == "string" or token.kind == "identifier"):
while token is not None and (
token.kind == "string" or token.kind == "identifier"
):
key = token.value

@@ -235,7 +266,7 @@ if token.kind == "string":

token_patterns = [
'({})'.format(self.patterns.get(t, re.escape(t)))
for t in self.tokens]
"({})".format(self.patterns.get(t, re.escape(t))) for t in self.tokens
]
if self.ignore:
token_patterns.append('(?:{})'.format(self.ignore))
self.token_re = re.compile('^(?:' + '|'.join(token_patterns) + ')')
token_patterns.append("(?:{})".format(self.ignore))
self.token_re = re.compile("^(?:" + "|".join(token_patterns) + ")")

@@ -251,3 +282,4 @@ def generate_tokens(self, source):

raise SyntaxError(
"Unexpected input for '{}' at '{}'".format(source, remainder))
"Unexpected input for '{}' at '{}'".format(source, remainder)
)
break

@@ -264,2 +296,3 @@ offset += mo.end()

start=start,
end=offset)
end=offset,
)

@@ -14,11 +14,12 @@ from __future__ import absolute_import, print_function, unicode_literals

operators = {}
IDENTIFIER_RE = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*$')
IDENTIFIER_RE = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
class SyntaxError(TemplateError):
@classmethod
def unexpected(cls, got):
return cls('Found: {} token, expected one of: !=, &&, (, *, **, +, -, ., /, <, <=, ==, >, >=, [, in,'
' ||'.format(got.value))
return cls(
"Found: {} token, expected one of: !=, &&, (, *, **, +, -, ., /, <, <=, ==, >, >=, [, in,"
" ||".format(got.value)
)

@@ -30,2 +31,3 @@

return fn
return wrap

@@ -35,17 +37,44 @@

tokenizer = Tokenizer(
'\\s+',
"\\s+",
{
'number': '[0-9]+(?:\\.[0-9]+)?',
'identifier': '[a-zA-Z_][a-zA-Z_0-9]*',
'string': '\'[^\']*\'|"[^"]*"',
"number": "[0-9]+(?:\\.[0-9]+)?",
"identifier": "[a-zA-Z_][a-zA-Z_0-9]*",
"string": "'[^']*'|\"[^\"]*\"",
# avoid matching these as prefixes of identifiers e.g., `insinutations`
'true': 'true(?![a-zA-Z_0-9])',
'false': 'false(?![a-zA-Z_0-9])',
'in': 'in(?![a-zA-Z_0-9])',
'null': 'null(?![a-zA-Z_0-9])',
"true": "true(?![a-zA-Z_0-9])",
"false": "false(?![a-zA-Z_0-9])",
"in": "in(?![a-zA-Z_0-9])",
"null": "null(?![a-zA-Z_0-9])",
},
[
'**', '+', '-', '*', '/', '[', ']', '.', '(', ')', '{', '}', ':', ',',
'>=', '<=', '<', '>', '==', '!=', '!', '&&', '||', 'true', 'false', 'in',
'null', 'number', 'identifier', 'string',
"**",
"+",
"-",
"*",
"/",
"[",
"]",
".",
"(",
")",
"{",
"}",
":",
",",
">=",
"<=",
"<",
">",
"==",
"!=",
"!",
"&&",
"||",
"true",
"false",
"in",
"null",
"number",
"identifier",
"string",
],

@@ -76,3 +105,3 @@ )

_interpolation_start_re = re.compile(r'\$?\${')
_interpolation_start_re = re.compile(r"\$?\${")

@@ -88,9 +117,12 @@

while True:
result.append(string[:mo.start()])
if mo.group() != '$${':
string = string[mo.end():]
parsed, offset = parse_until_terminator(string, context, '}')
result.append(string[: mo.start()])
if mo.group() != "$${":
string = string[mo.end() :]
parsed, offset = parse_until_terminator(string, context, "}")
if isinstance(parsed, (list, dict)):
raise TemplateError(
"interpolation of '{}' produced an array or object".format(string[:offset]))
"interpolation of '{}' produced an array or object".format(
string[:offset]
)
)
if parsed is None:

@@ -100,6 +132,6 @@ result.append("")

result.append(to_str(parsed))
string = string[offset + 1:]
string = string[offset + 1 :]
else: # found `$${`
result.append('${')
string = string[mo.end():]
result.append("${")
string = string[mo.end() :]

@@ -110,3 +142,3 @@ mo = _interpolation_start_re.search(string)

break
return ''.join(result)
return "".join(result)

@@ -117,23 +149,25 @@

combined = "|".join(allowed) + "$"
unknownKeys = [key for key in sorted(template)
if not re.match(combined, key)]
unknownKeys = [key for key in sorted(template) if not re.match(combined, key)]
if unknownKeys:
raise TemplateError(allowed[0].replace('\\', '') +
" has undefined properties: " + " ".join(unknownKeys))
raise TemplateError(
allowed[0].replace("\\", "")
+ " has undefined properties: "
+ " ".join(unknownKeys)
)
@operator('$eval')
@operator("$eval")
def eval(template, context):
checkUndefinedProperties(template, [r'\$eval'])
if not isinstance(template['$eval'], string):
checkUndefinedProperties(template, [r"\$eval"])
if not isinstance(template["$eval"], string):
raise TemplateError("$eval must be given a string expression")
return parse(template['$eval'], context)
return parse(template["$eval"], context)
@operator('$flatten')
@operator("$flatten")
def flatten(template, context):
checkUndefinedProperties(template, [r'\$flatten'])
value = renderValue(template['$flatten'], context)
checkUndefinedProperties(template, [r"\$flatten"])
value = renderValue(template["$flatten"], context)
if not isinstance(value, list):
raise TemplateError('$flatten value must evaluate to an array')
raise TemplateError("$flatten value must evaluate to an array")

@@ -147,11 +181,12 @@ def gen():

yield e
return list(gen())
@operator('$flattenDeep')
@operator("$flattenDeep")
def flattenDeep(template, context):
checkUndefinedProperties(template, [r'\$flattenDeep'])
value = renderValue(template['$flattenDeep'], context)
checkUndefinedProperties(template, [r"\$flattenDeep"])
value = renderValue(template["$flattenDeep"], context)
if not isinstance(value, list):
raise TemplateError('$flattenDeep value must evaluate to an array')
raise TemplateError("$flattenDeep value must evaluate to an array")

@@ -169,8 +204,11 @@ def gen(value):

@operator('$fromNow')
@operator("$fromNow")
def fromNow(template, context):
checkUndefinedProperties(template, [r'\$fromNow', 'from'])
offset = renderValue(template['$fromNow'], context)
reference = renderValue(
template['from'], context) if 'from' in template else context.get('now')
checkUndefinedProperties(template, [r"\$fromNow", "from"])
offset = renderValue(template["$fromNow"], context)
reference = (
renderValue(template["from"], context)
if "from" in template
else context.get("now")
)

@@ -182,11 +220,11 @@ if not isinstance(offset, string):

@operator('$if')
@operator("$if")
def ifConstruct(template, context):
checkUndefinedProperties(template, [r'\$if', 'then', 'else'])
condition = parse(template['$if'], context)
checkUndefinedProperties(template, [r"\$if", "then", "else"])
condition = parse(template["$if"], context)
try:
if condition:
rv = template['then']
rv = template["then"]
else:
rv = template['else']
rv = template["else"]
except KeyError:

@@ -197,19 +235,19 @@ return DeleteMarker

@operator('$json')
@operator("$json")
def jsonConstruct(template, context):
checkUndefinedProperties(template, [r'\$json'])
value = renderValue(template['$json'], context)
checkUndefinedProperties(template, [r"\$json"])
value = renderValue(template["$json"], context)
if containsFunctions(value):
raise TemplateError('evaluated template contained uncalled functions')
return json.dumps(value, separators=(',', ':'), sort_keys=True, ensure_ascii=False)
raise TemplateError("evaluated template contained uncalled functions")
return json.dumps(value, separators=(",", ":"), sort_keys=True, ensure_ascii=False)
@operator('$let')
@operator("$let")
def let(template, context):
checkUndefinedProperties(template, [r'\$let', 'in'])
if not isinstance(template['$let'], dict):
checkUndefinedProperties(template, [r"\$let", "in"])
if not isinstance(template["$let"], dict):
raise TemplateError("$let value must be an object")
subcontext = context.copy()
initial_result = renderValue(template['$let'], context)
initial_result = renderValue(template["$let"], context)
if not isinstance(initial_result, dict):

@@ -219,7 +257,9 @@ raise TemplateError("$let value must be an object")

if not IDENTIFIER_RE.match(k):
raise TemplateError("top level keys of $let must follow /[a-zA-Z_][a-zA-Z0-9_]*/")
raise TemplateError(
"top level keys of $let must follow /[a-zA-Z_][a-zA-Z0-9_]*/"
)
else:
subcontext[k] = v
try:
in_expression = template['in']
in_expression = template["in"]
except KeyError:

@@ -230,7 +270,7 @@ raise TemplateError("$let operator requires an `in` clause")

@operator('$map')
@operator("$map")
def map(template, context):
EACH_RE = r'each\([a-zA-Z_][a-zA-Z0-9_]*(,\s*([a-zA-Z_][a-zA-Z0-9_]*))?\)'
checkUndefinedProperties(template, [r'\$map', EACH_RE])
value = renderValue(template['$map'], context)
EACH_RE = r"each\([a-zA-Z_][a-zA-Z0-9_]*(,\s*([a-zA-Z_][a-zA-Z0-9_]*))?\)"
checkUndefinedProperties(template, [r"\$map", EACH_RE])
value = renderValue(template["$map"], context)
if not isinstance(value, list) and not isinstance(value, dict):

@@ -241,8 +281,7 @@ raise TemplateError("$map value must evaluate to an array or object")

each_keys = [k for k in template if k.startswith('each(')]
each_keys = [k for k in template if k.startswith("each(")]
if len(each_keys) != 1:
raise TemplateError(
"$map requires exactly one other property, each(..)")
raise TemplateError("$map requires exactly one other property, each(..)")
each_key = each_keys[0]
each_args = [x.strip() for x in each_key[5:-1].split(',')]
each_args = [x.strip() for x in each_key[5:-1].split(",")]
each_var = each_args[0]

@@ -259,9 +298,10 @@ each_idx = each_args[1] if len(each_args) > 1 else None

else:
subcontext[each_var] = elt['val'] if is_obj else elt
subcontext[each_idx] = elt['key'] if is_obj else i
subcontext[each_var] = elt["val"] if is_obj else elt
subcontext[each_idx] = elt["key"] if is_obj else i
elt = renderValue(each_template, subcontext)
if elt is not DeleteMarker:
yield elt
if is_obj:
value = [{'key': v[0], 'val': v[1]} for v in value.items()]
value = [{"key": v[0], "val": v[1]} for v in value.items()]
v = dict()

@@ -271,3 +311,6 @@ for e in gen(value):

raise TemplateError(
"$map on objects expects {0} to evaluate to an object".format(each_key))
"$map on objects expects {0} to evaluate to an object".format(
each_key
)
)
v.update(e)

@@ -279,13 +322,13 @@ return v

@operator('$match')
@operator("$match")
def matchConstruct(template, context):
checkUndefinedProperties(template, [r'\$match'])
checkUndefinedProperties(template, [r"\$match"])
if not isinstance(template['$match'], dict):
if not isinstance(template["$match"], dict):
raise TemplateError("$match can evaluate objects only")
result = []
for condition in sorted(template['$match']):
for condition in sorted(template["$match"]):
if parse(condition, context):
result.append(renderValue(template['$match'][condition], context))
result.append(renderValue(template["$match"][condition], context))

@@ -295,13 +338,13 @@ return result

@operator('$switch')
@operator("$switch")
def switch(template, context):
checkUndefinedProperties(template, [r'\$switch'])
checkUndefinedProperties(template, [r"\$switch"])
if not isinstance(template['$switch'], dict):
if not isinstance(template["$switch"], dict):
raise TemplateError("$switch can evaluate objects only")
result = []
for condition in template['$switch']:
if not condition == '$default' and parse(condition, context):
result.append(renderValue(template['$switch'][condition], context))
for condition in template["$switch"]:
if not condition == "$default" and parse(condition, context):
result.append(renderValue(template["$switch"][condition], context))

@@ -312,4 +355,4 @@ if len(result) > 1:

if len(result) == 0:
if '$default' in template['$switch']:
result.append(renderValue(template['$switch']['$default'], context))
if "$default" in template["$switch"]:
result.append(renderValue(template["$switch"]["$default"], context))

@@ -319,9 +362,8 @@ return result[0] if len(result) > 0 else DeleteMarker

@operator('$merge')
@operator("$merge")
def merge(template, context):
checkUndefinedProperties(template, [r'\$merge'])
value = renderValue(template['$merge'], context)
checkUndefinedProperties(template, [r"\$merge"])
value = renderValue(template["$merge"], context)
if not isinstance(value, list) or not all(isinstance(e, dict) for e in value):
raise TemplateError(
"$merge value must evaluate to an array of objects")
raise TemplateError("$merge value must evaluate to an array of objects")
v = dict()

@@ -333,9 +375,8 @@ for e in value:

@operator('$mergeDeep')
@operator("$mergeDeep")
def merge(template, context):
checkUndefinedProperties(template, [r'\$mergeDeep'])
value = renderValue(template['$mergeDeep'], context)
checkUndefinedProperties(template, [r"\$mergeDeep"])
value = renderValue(template["$mergeDeep"], context)
if not isinstance(value, list) or not all(isinstance(e, dict) for e in value):
raise TemplateError(
"$mergeDeep value must evaluate to an array of objects")
raise TemplateError("$mergeDeep value must evaluate to an array of objects")

@@ -354,2 +395,3 @@ def merge(l, r):

return r
if len(value) == 0:

@@ -360,6 +402,6 @@ return {}

@operator('$reverse')
@operator("$reverse")
def reverse(template, context):
checkUndefinedProperties(template, [r'\$reverse'])
value = renderValue(template['$reverse'], context)
checkUndefinedProperties(template, [r"\$reverse"])
value = renderValue(template["$reverse"], context)
if not isinstance(value, list):

@@ -370,12 +412,12 @@ raise TemplateError("$reverse value must evaluate to an array of objects")

@operator('$sort')
@operator("$sort")
def sort(template, context):
BY_RE = r'by\([a-zA-Z_][a-zA-Z0-9_]*\)'
checkUndefinedProperties(template, [r'\$sort', BY_RE])
value = renderValue(template['$sort'], context)
BY_RE = r"by\([a-zA-Z_][a-zA-Z0-9_]*\)"
checkUndefinedProperties(template, [r"\$sort", BY_RE])
value = renderValue(template["$sort"], context)
if not isinstance(value, list):
raise TemplateError('$sorted values to be sorted must have the same type')
raise TemplateError("$sorted values to be sorted must have the same type")
# handle by(..) if given, applying the schwartzian transform
by_keys = [k for k in template if k.startswith('by(')]
by_keys = [k for k in template if k.startswith("by(")]
if len(by_keys) == 1:

@@ -391,2 +433,3 @@ by_key = by_keys[0]

yield parse(by_expr, subcontext), e
to_sort = list(xform())

@@ -396,3 +439,3 @@ elif len(by_keys) == 0:

else:
raise TemplateError('only one by(..) is allowed')
raise TemplateError("only one by(..) is allowed")

@@ -405,5 +448,5 @@ # check types

if eltype in (list, dict, bool, type(None)):
raise TemplateError('$sorted values to be sorted must have the same type')
raise TemplateError("$sorted values to be sorted must have the same type")
if not all(isinstance(e[0], eltype) for e in to_sort):
raise TemplateError('$sorted values to be sorted must have the same type')
raise TemplateError("$sorted values to be sorted must have the same type")

@@ -415,3 +458,3 @@ # unzip the schwartzian transform

def containsFunctions(rendered):
if hasattr(rendered, '__call__'):
if hasattr(rendered, "__call__"):
return True

@@ -445,7 +488,6 @@ elif isinstance(rendered, list):

for k, v in viewitems(template):
if k.startswith('$$'):
if k.startswith("$$"):
k = k[1:]
elif k.startswith('$') and IDENTIFIER_RE.match(k[1:]):
raise TemplateError(
'$<identifier> is reserved; use $$<identifier>')
elif k.startswith("$") and IDENTIFIER_RE.match(k[1:]):
raise TemplateError("$<identifier> is reserved; use $$<identifier>")
else:

@@ -458,11 +500,13 @@ k = interpolate(k, context)

if IDENTIFIER_RE.match(k):
e.add_location('.{}'.format(k))
e.add_location(".{}".format(k))
else:
e.add_location('[{}]'.format(json.dumps(k)))
e.add_location("[{}]".format(json.dumps(k)))
raise
if v is not DeleteMarker:
yield k, v
return dict(updated())
elif isinstance(template, list):
def updated():

@@ -475,3 +519,3 @@ for i, e in enumerate(template):

except JSONTemplateError as e:
e.add_location('[{}]'.format(i))
e.add_location("[{}]".format(i))
raise

@@ -478,0 +522,0 @@

@@ -20,7 +20,6 @@ from __future__ import absolute_import, print_function, unicode_literals

def __str__(self):
location = ' at template' + ''.join(self.location)
location = " at template" + "".join(self.location)
return "{}{}: {}".format(
self.__class__.__name__,
location if self.location else '',
self.args[0])
self.__class__.__name__, location if self.location else "", self.args[0]
)

@@ -37,12 +36,15 @@

# Regular expression matching: X days Y hours Z minutes
# todo: support hr, wk, yr
FROMNOW_RE = re.compile(''.join([
r'^(\s*(?P<years>\d+)\s*y(ears?)?)?',
r'(\s*(?P<months>\d+)\s*mo(nths?)?)?',
r'(\s*(?P<weeks>\d+)\s*w(eeks?)?)?',
r'(\s*(?P<days>\d+)\s*d(ays?)?)?',
r'(\s*(?P<hours>\d+)\s*h(ours?)?)?',
r'(\s*(?P<minutes>\d+)\s*m(in(utes?)?)?)?\s*',
r'(\s*(?P<seconds>\d+)\s*s(ec(onds?)?)?)?\s*$',
]))
FROMNOW_RE = re.compile(
"".join(
[
r"^(\s*(?P<years>\d+)\s*(years|year|yr|y))?",
r"(\s*(?P<months>\d+)\s*(months|month|mo))?",
r"(\s*(?P<weeks>\d+)\s*(weeks|week|wk|w))?",
r"(\s*(?P<days>\d+)\s*(days|day|d))?",
r"(\s*(?P<hours>\d+)\s*(hours|hour|hr|h))?",
r"(\s*(?P<minutes>\d+)\s*(minutes|minute|min|m))?",
r"(\s*(?P<seconds>\d+)\s*(seconds|second|sec|s))?\s*$",
]
)
)

@@ -55,6 +57,6 @@

offset = offset.lstrip()
if offset.startswith('-'):
if offset.startswith("-"):
future = False
offset = offset[1:].lstrip()
if offset.startswith('+'):
if offset.startswith("+"):
offset = offset[1:].lstrip()

@@ -65,3 +67,3 @@

if m is None:
raise ValueError("offset string: '%s' does not parse" % offset)
raise TemplateError("offset string: '%s' does not parse" % offset)

@@ -74,18 +76,18 @@ # In order to calculate years and months we need to calculate how many days

seconds = 0
if m.group('years'):
if m.group("years"):
# forget leap years, a year is 365 days
years = int(m.group('years'))
years = int(m.group("years"))
days += 365 * years
if m.group('months'):
if m.group("months"):
# assume "month" means 30 days
months = int(m.group('months'))
months = int(m.group("months"))
days += 30 * months
days += int(m.group('days') or 0)
hours += int(m.group('hours') or 0)
minutes += int(m.group('minutes') or 0)
seconds += int(m.group('seconds') or 0)
days += int(m.group("days") or 0)
hours += int(m.group("hours") or 0)
minutes += int(m.group("minutes") or 0)
seconds += int(m.group("seconds") or 0)
# Offset datetime from utc
delta = datetime.timedelta(
weeks=int(m.group('weeks') or 0),
weeks=int(m.group("weeks") or 0),
days=days,

@@ -98,4 +100,3 @@ hours=hours,

if isinstance(reference, string):
reference = datetime.datetime.strptime(
reference, '%Y-%m-%dT%H:%M:%S.%fZ')
reference = datetime.datetime.strptime(reference, "%Y-%m-%dT%H:%M:%S.%fZ")
elif reference is None:

@@ -106,3 +107,3 @@ reference = datetime.datetime.utcnow()

datefmt_re = re.compile(r'(\.[0-9]{3})[0-9]*(\+00:00)?')
datefmt_re = re.compile(r"(\.[0-9]{3})[0-9]*(\+00:00)?")

@@ -112,7 +113,7 @@

if isinstance(v, bool):
return {True: 'true', False: 'false'}[v]
return {True: "true", False: "false"}[v]
elif isinstance(v, list):
return ','.join(to_str(e) for e in v)
return ",".join(to_str(e) for e in v)
elif v is None:
return 'null'
return "null"
elif isinstance(v, string):

@@ -127,9 +128,9 @@ return v

try:
string = date.isoformat(timespec='microseconds')
string = date.isoformat(timespec="microseconds")
# py2.7 to py3.5 does not have timespec
except TypeError as e:
string = date.isoformat()
if string.find('.') == -1:
string += '.000'
string = datefmt_re.sub(r'\1Z', string)
if string.find(".") == -1:
string += ".000"
string = datefmt_re.sub(r"\1Z", string)
return string

@@ -136,0 +137,0 @@

@@ -9,2 +9,3 @@ import sys

"""Create a base class with a metaclass."""
# This requires a bit of explanation: the basic idea is to make a dummy

@@ -14,8 +15,8 @@ # metaclass for one level of class instantiation that replaces itself with

class metaclass(meta):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
return type.__new__(metaclass, 'temporary_class', (), {})
return type.__new__(metaclass, "temporary_class", (), {})
# https://github.com/benjaminp/six/blob/2c3492a9f16d294cd5e6b43d6110c5a3a2e58b4c/six.py#L578

@@ -22,0 +23,0 @@ if sys.version_info[0] == 3:

Metadata-Version: 2.1
Name: json-e
Version: 4.5.3
Version: 4.6.0
Summary: A data-structure parameterization system written for embedding context in JSON objects

@@ -5,0 +5,0 @@ Home-page: https://json-e.js.org

+16
-13

@@ -5,26 +5,29 @@ import json

version = "4.5.3"
version = "4.6.0"
description='A data-structure parameterization system written for embedding context in JSON objects'
description = "A data-structure parameterization system written for embedding context in JSON objects"
long_description = '''\
long_description = """\
{description}.
See https://json-e.js.org for usage information.
'''.format(description=description)
""".format(
description=description
)
setup(name='json-e',
setup(
name="json-e",
version=version,
description=description,
long_description=long_description,
author='Dustin J. Mitchell',
url='https://json-e.js.org',
author_email='dustin@mozilla.com',
packages=['jsone'],
license='MPL2',
author="Dustin J. Mitchell",
url="https://json-e.js.org",
author_email="dustin@mozilla.com",
packages=["jsone"],
license="MPL2",
extras_require={
'release': [
'towncrier',
"release": [
"towncrier",
],
}
},
)