mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) More helpful messages when formula probably needs to use Table.all
Summary: Raise an exception with a customised message for two cases when a user tries on operation directly on a table without `.all`: 1. For `Table.Col`, where `Col` is an existing column, suggest `Table.all.Col`. If `Col` doesn't exist as a column, fall back to the standard AttributeError. 2. When iterating directly over a table, e.g. `[r for r in Table]`, suggest looping over `Table.all` instead. Test Plan: Added Python unit tests. Reviewers: georgegevoian Reviewed By: georgegevoian Differential Revision: https://phab.getgrist.com/D3593
This commit is contained in:
parent
56e8e1f4b3
commit
eac1f26f3e
@ -133,6 +133,20 @@ class UserTable(object):
|
||||
# the constructor.
|
||||
return []
|
||||
|
||||
def __getattr__(self, item):
|
||||
if self.table.has_column(item):
|
||||
raise AttributeError(
|
||||
"To retrieve all values in a column, use `{table_id}.all.{item}`. "
|
||||
"Tables have no attribute '{item}'".format(table_id=self.table.table_id, item=item)
|
||||
)
|
||||
super(UserTable, self).__getattribute__(item)
|
||||
|
||||
def __iter__(self):
|
||||
raise TypeError(
|
||||
"To iterate (loop) over all records in a table, use `{table_id}.all`. "
|
||||
"Tables are not directly iterable.".format(table_id=self.table.table_id)
|
||||
)
|
||||
|
||||
|
||||
class Table(object):
|
||||
"""
|
||||
|
@ -157,6 +157,81 @@ else:
|
||||
self.assertFormulaError(self.engine.get_formula_error('Math', 'custom_err', 3),
|
||||
Exception, "hello")
|
||||
|
||||
def test_missing_all_attribute(self):
|
||||
# Test that `Table.Col` raises a helpful AttributeError suggesting to use `Table.all.Col`.
|
||||
sample = testutil.parse_test_sample({
|
||||
"SCHEMA": [
|
||||
[1, "Table", [
|
||||
[11, "A", "Any", True, "Table.id", "", ""],
|
||||
[12, "B", "Any", True, "Table.id2", "", ""],
|
||||
]]
|
||||
],
|
||||
"DATA": {
|
||||
"Table": [
|
||||
["id"],
|
||||
[1],
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
self.load_sample(sample)
|
||||
|
||||
# `Table.id` gives a custom message because `id` is an existing column.
|
||||
self.assertFormulaError(
|
||||
self.engine.get_formula_error('Table', 'A', 1),
|
||||
AttributeError,
|
||||
'To retrieve all values in a column, use `Table.all.id`. '
|
||||
"Tables have no attribute 'id'"
|
||||
+ six.PY3 * (
|
||||
"\n\nAn `AttributeError` occurs when the code contains something like\n"
|
||||
" `object.x`\n"
|
||||
"and `x` is not a method or attribute (variable) belonging to `object`."
|
||||
)
|
||||
)
|
||||
|
||||
# `Table.id2` gives a standard message because `id2` is not an existing column.
|
||||
error = self.engine.get_formula_error('Table', 'B', 1).error
|
||||
message = str(error)
|
||||
self.assertNotIn('Table.all', message)
|
||||
self.assertIn("'UserTable' object has no attribute 'id2'", message)
|
||||
|
||||
def test_missing_all_iteration(self):
|
||||
sample = testutil.parse_test_sample({
|
||||
"SCHEMA": [
|
||||
[1, "MyTable", [
|
||||
[11, "A", "Any", True, "list(MyTable)", "", ""],
|
||||
[12, "B", "Any", True, "list(MyTable.all)", "", ""],
|
||||
]]
|
||||
],
|
||||
"DATA": {
|
||||
"MyTable": [
|
||||
["id"],
|
||||
[1],
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
self.load_sample(sample)
|
||||
|
||||
# `list(MyTable)` gives a custom message suggesting `.all`.
|
||||
self.assertFormulaError(
|
||||
self.engine.get_formula_error('MyTable', 'A', 1),
|
||||
TypeError,
|
||||
"To iterate (loop) over all records in a table, use `MyTable.all`. "
|
||||
"Tables are not directly iterable."
|
||||
+ six.PY3 * (
|
||||
'\n\nA `TypeError` is usually caused by trying\n'
|
||||
'to combine two incompatible types of objects,\n'
|
||||
'by calling a function with the wrong type of object,\n'
|
||||
'or by trying to do an operation not allowed on a given type of object.'
|
||||
)
|
||||
)
|
||||
|
||||
# `list(MyTable.all)` works correctly.
|
||||
self.assertTableData('MyTable', data=[
|
||||
['id', 'A', 'B'],
|
||||
[ 1, objtypes.RaisedException(TypeError()), [objtypes.RecordStub('MyTable', 1)]],
|
||||
])
|
||||
|
||||
def test_lookup_state(self):
|
||||
# Bug https://phab.getgrist.com/T297 was caused by lookup maps getting corrupted while
|
||||
|
Loading…
Reference in New Issue
Block a user