Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions src/app_model/expressions/_expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,45 @@ def __init__(self, test: Expr, body: Expr, orelse: Expr, **kwargs: Any) -> None:
)


class Tuple(Expr, ast.Tuple):
"""A tuple expression.

`elts` is a list of expressions.
"""

def __init__(
self, elts: Sequence[Expr], ctx: ast.expr_context = LOAD, **kwargs: Any
) -> None:
kwargs["ctx"] = ctx
super().__init__(elts=[Expr._cast(e) for e in elts], **kwargs)


class List(Expr, ast.List):
"""A tuple expression.

`elts` is a list of expressions.
"""

def __init__(
self, elts: Sequence[Expr], ctx: ast.expr_context = LOAD, **kwargs: Any
) -> None:
kwargs["ctx"] = ctx
super().__init__(elts=[Expr._cast(e) for e in elts], **kwargs)


class Set(Expr, ast.Set):
"""A tuple expression.

`elts` is a list of expressions.
"""

def __init__(
self, elts: Sequence[Expr], ctx: ast.expr_context = LOAD, **kwargs: Any
) -> None:
kwargs["ctx"] = ctx
super().__init__(elts=[Expr._cast(e) for e in elts], **kwargs)


class ExprTransformer(ast.NodeTransformer):
"""Transformer that converts an ast.expr into an `Expr`.

Expand Down Expand Up @@ -568,6 +607,15 @@ def __str__(self) -> str:
def visit_Name(self, node: ast.Name) -> None:
self.write(node.id)

def visit_Tuple(self, node: ast.Tuple) -> None:
self.write(f'({", ".join(map(str, node.elts))})')

def visit_Set(self, node: ast.Set) -> None:
self.write("{" + ", ".join(map(str, node.elts)) + "}")

def visit_List(self, node: ast.List) -> None:
self.write(f'[{", ".join(map(str, node.elts))}]')

def visit_ContextKey(self, node: ContextKey) -> None:
return self.visit_Name(node)

Expand Down
12 changes: 6 additions & 6 deletions tests/test_context/test_expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ def test_iter_names():
"1",
"3.14",
"True",
"1 in {1, 2, 3}",
"1 in [1, 2, 3]",
"1 in (1, 2, 3)",
"False",
"None",
"hieee",
Expand All @@ -183,10 +186,7 @@ def test_iter_names():
"my.attribute", # Attribute
"__import__(something)", # Call
'print("hi")',
"(1,)", # tuples not yet supported
'{"key": "val"}', # dicts not yet supported
'{"hi"}', # set constant
"[]", # lists constant
"mylist[0]", # Index
"mylist[0:1]", # Slice
'f"a"', # JoinedStr
Expand Down Expand Up @@ -228,13 +228,13 @@ def test_safe_eval():
assert safe_eval(expr, {"x": 1}) == 3
assert safe_eval(True) is True
assert safe_eval(False) is False
assert safe_eval("[1,2,3]") == [1, 2, 3]
assert safe_eval("(1,2,3)") == (1, 2, 3)
assert safe_eval("{1,2,3}") == {1, 2, 3}

with pytest.raises(SyntaxError, match="Type 'Call' not supported"):
safe_eval("func(x)")

with pytest.raises(SyntaxError, match="Type 'Set' not supported"):
safe_eval("{1,2,3}")


def test_eval_kwargs():
expr = parse_expression("a + b")
Expand Down