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
4 changes: 2 additions & 2 deletions cpp/perspective/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,9 @@ if (PSP_WASM_BUILD)
if(CMAKE_BUILD_TYPE_LOWER STREQUAL debug)
set(OPT_FLAGS " \
-O0 \
-g4 \
-g3 \
-gsource-map \
--profiling \
-s WARN_UNALIGNED=1 \
-Wcast-align \
-Wover-aligned \
")
Expand Down
31 changes: 31 additions & 0 deletions packages/perspective/test/js/expressions/functionality.js
Original file line number Diff line number Diff line change
Expand Up @@ -2614,6 +2614,26 @@ module.exports = (perspective) => {
'max(100, "a")': "float",
"more columns": "string",
});

let i = 0;
for (const alias of [
"abc",
"def",
expressions[2],
"new column",
expressions[4],
expressions[5],
"more columns",
expressions[7],
expressions[8],
expressions[9],
expressions[10],
]) {
expect(results.expression_alias[alias]).toEqual(
expressions[i]
);
i++;
}
table.delete();
});

Expand All @@ -2638,6 +2658,7 @@ module.exports = (perspective) => {
'max(100, "a")', // valid
];
const results = await table.validate_expressions(expressions);

expect(results.expression_schema).toEqual({
'"a" + "d"': "float",
'"c"': "string",
Expand All @@ -2646,6 +2667,11 @@ module.exports = (perspective) => {
'max(100, "a")': "float",
"concat(\"c\", ' ', \"c\", 'abc')": "string",
});

for (const expr of expressions) {
expect(results.expression_alias[expr]).toEqual(expr);
}

table.delete();
});

Expand All @@ -2672,6 +2698,11 @@ module.exports = (perspective) => {
"bucket(\"b\", 'M')": "date",
'upper("c")': "string",
});

for (const expr of expressions) {
expect(results.expression_alias[expr]).toEqual(expr);
}

table.delete();
});

Expand Down
8 changes: 7 additions & 1 deletion python/perspective/perspective/table/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def validate_expressions(self, expressions, as_string=False):
as_string (:obj:`bool`): If True, returns the data types as string
representations so they can be serialized.
"""
validated = {"expression_schema": {}, "errors": {}}
validated = {"expression_schema": {}, "errors": {}, "expression_alias": {}}

if len(expressions) == 0:
return validated
Expand All @@ -195,9 +195,15 @@ def validate_expressions(self, expressions, as_string=False):
expression_schema = validation_results.get_expression_schema()
expression_errors = validation_results.get_expression_errors()

for expression in expressions:
# expression_alias can be used to map the alias to the
# full expression string in the UI.
validated["expression_alias"][expression[0]] = expression[1]

for (alias, dtype) in iteritems(expression_schema):
if not as_string:
dtype = _str_to_pythontype(dtype)

validated["expression_schema"][alias] = expression_schema[alias]

for (alias, error) in iteritems(expression_errors):
Expand Down
5 changes: 4 additions & 1 deletion python/perspective/perspective/tests/manager/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,10 @@ def test_manager_table_validate_expressions(self):
"expression_schema": {
"abc": "float"
},
"errors": {}
"errors": {},
"expression_alias": {
"abc": '// abc \n "a" + "a"'
}
}
})

Expand Down
64 changes: 57 additions & 7 deletions python/perspective/perspective/tests/table/test_view_expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def test_table_validate_expressions_empty(self):
table = Table({"a": [1, 2, 3, 4], "b": [5, 6, 7, 8]})
validate = table.validate_expressions([])
assert validate["expression_schema"] == {}
assert validate["expression_alias"] == {}
assert validate["errors"] == {}

def test_view_expression_schema_empty(self):
Expand All @@ -27,18 +28,61 @@ def test_view_expression_schema_empty(self):
assert view.to_columns() == {"a": [1, 2, 3, 4], "b": [5, 6, 7, 8]}
assert view.expression_schema() == {}

def test_view_validate_expressions_alias_map_errors(self):
table = Table({"a": [1, 2, 3, 4], "b": [5, 6, 7, 8]})
expressions = [
'// x\n"a"',
'// y\n"b" * 0.5',
"// c\n'abcdefg'",
"// d\ntrue and false",
'// e\nfloat("a") > 2 ? null : 1',
"// f\ntoday()",
"// g\nnow()",
"// h\nlength(123)",
]

validated = table.validate_expressions(expressions)

aliases = ["x", "y", "c", "d", "e", "f", "g", "h"]

# Errored should also be in aliases
for idx, alias in enumerate(aliases):
assert validated["expression_alias"][alias] == expressions[idx]

def test_view_validate_expressions_alias_map(self):
table = Table({"a": [1, 2, 3, 4], "b": [5, 6, 7, 8]})
expressions = [
'// x\n"a"',
'// y\n"b" * 0.5',
"// c\n'abcdefg'",
"// d\ntrue and false",
'// e\nfloat("a") > 2 ? null : 1',
"// f\ntoday()",
"// g\nnow()",
"// h\nlength('abcd')",
]

validated = table.validate_expressions(expressions)

aliases = ["x", "y", "c", "d", "e", "f", "g", "h"]

for idx, alias in enumerate(aliases):
assert validated["expression_alias"][alias] == expressions[idx]

def test_view_expression_schema_all_types(self):
table = Table({"a": [1, 2, 3, 4], "b": [5, 6, 7, 8]})
view = table.view(expressions=[
expressions = [
'"a"',
'"b" * 0.5',
"'abcdefg'",
"true and false",
'float("a") > 2 ? null : 1',
"today()",
"now()",
"length('abcd')"
])
"length('abcd')",
]

view = table.view(expressions=expressions)
assert view.expression_schema() == {
'"a"': int,
'"b" * 0.5': float,
Expand All @@ -47,12 +91,13 @@ def test_view_expression_schema_all_types(self):
'float("a") > 2 ? null : 1': float,
"today()": date,
"now()": datetime,
"length('abcd')": float
"length('abcd')": float,
}

result = view.to_columns()
today = datetime(date.today().year, date.today().month, date.today().day)
del result["now()"] # no need to match datetime.now()

assert result == {
"a": [1, 2, 3, 4],
"b": [5, 6, 7, 8],
Expand All @@ -65,12 +110,17 @@ def test_view_expression_schema_all_types(self):
"length('abcd')": [4 for _ in range(4)]
}

validated = table.validate_expressions(expressions)

for expr in expressions:
assert validated["expression_alias"][expr] == expr

def test_table_validate_expressions_with_errors(self):
table = Table({"a": [1, 2, 3, 4], "b": [5, 6, 7, 8]})
validate = table.validate_expressions(
['"Sales" + "Profit"', "datetime()", "string()", "for () {}"]
)
expressions = ['"Sales" + "Profit"', "datetime()", "string()", "for () {}"]
validate = table.validate_expressions(expressions)
assert validate["expression_schema"] == {}
assert validate["expression_alias"] == {expr: expr for expr in expressions}
assert validate["errors"] == {
'"Sales" + "Profit"': {
"column": 0,
Expand Down