Skip to content

Commit abd2667

Browse files
committed
Better errors
1 parent 976319a commit abd2667

7 files changed

+33
-20
lines changed

preql/api.py

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from . import settings
44
from . import pql_ast as ast
55
from . import pql_objects as objects
6-
from .utils import classify
76
from .interpreter import Interpreter
87
from .sql_interface import create_engine
98
from .pql_types import T

preql/compiler.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ def compile_to_inst(state: State, proj: ast.Projection):
251251
@dy
252252
def compile_to_inst(state: State, order: ast.Order):
253253
table = cast_to_instance(state, order.table)
254-
assert_type(table.type, T.table, state, order, "'order'")
254+
assert_type(table.type, T.table, order, "'order'")
255255

256256
with state.use_scope(table.all_attrs()):
257257
fields = cast_to_instance(state, order.fields)
@@ -447,7 +447,7 @@ def compile_to_inst(state: State, cmp: ast.Compare):
447447
@dy
448448
def compile_to_inst(state: State, neg: ast.Neg):
449449
expr = cast_to_instance(state, neg.expr)
450-
assert_type(expr.type, T.number, state, neg, "Negation")
450+
assert_type(expr.type, T.number, neg, "Negation")
451451

452452
return make_instance(sql.Neg(expr.code), expr.type, [expr])
453453

@@ -732,7 +732,7 @@ def compile_to_inst(state: State, rps: ast.ParameterizedSqlCode):
732732
def compile_to_inst(state: State, s: ast.Slice):
733733
obj = cast_to_instance(state, s.obj)
734734

735-
assert_type(obj.type, T.union[T.string, T.table], state, s, "Slice")
735+
assert_type(obj.type, T.union[T.string, T.table], s, "Slice")
736736

737737
instances = [obj]
738738
if s.range.start:
@@ -773,7 +773,7 @@ def compile_to_inst(state: State, sel: ast.Selection):
773773
).set_text_ref(sel.text_ref)
774774
return compile_to_inst(state, slice)
775775

776-
assert_type(table.type, T.table, state, sel, "Selection")
776+
assert_type(table.type, T.table, sel, "Selection")
777777

778778
with state.use_scope({n:projected(c) for n, c in table.all_attrs().items()}):
779779
conds = cast_to_instance(state, sel.conds)

preql/evaluate.py

+19-8
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from pathlib import Path
44

55
from .utils import safezip, dataclass, SafeDict, listgen
6-
from .interp_common import assert_type, exclude_fields, call_builtin_func, is_global_scope
6+
from .interp_common import assert_type, exclude_fields, call_builtin_func, is_global_scope, cast_to_python_string, cast_to_python_int
77
from .exceptions import InsufficientAccessLevel, ReturnSignal, Signal
88
from . import exceptions as exc
99
from . import pql_objects as objects
@@ -56,21 +56,32 @@ def resolve(state: State, col_def: ast.ColumnDef):
5656
assert not query
5757

5858
if isinstance(coltype, objects.SelectedColumnInstance):
59-
x = T.t_relation[coltype.type](rel={'table': coltype.parent.type, 'column': coltype.name, 'key': False})
59+
table = coltype.parent.type
60+
if 'name' not in table.options:
61+
# XXX better test for persistence
62+
raise Signal.make(T.TypeError, col_def.type, "Tables provided as relations must be persistent.")
63+
64+
x = T.t_relation[coltype.type](rel={'table': table, 'column': coltype.name, 'key': False})
6065
return x.replace(_nullable=coltype.type._nullable) # inherit is_nullable (TODO: use sumtypes?)
6166

6267
elif coltype <= T.table:
68+
if 'name' not in coltype.options:
69+
# XXX better test for persistence
70+
raise Signal.make(T.TypeError, col_def.type, "Tables provided as relations must be persistent.")
71+
6372
x = T.t_relation[T.t_id.as_nullable()](rel={'table': coltype, 'column': 'id', 'key': True})
6473
return x.replace(_nullable=coltype._nullable) # inherit is_nullable (TODO: use sumtypes?)
6574

6675
return coltype(default=col_def.default)
6776

6877
@dy
6978
def resolve(state: State, type_: ast.Type):
70-
t = evaluate(state, type_.name)
79+
t = evaluate(state, type_.type_obj)
7180
if isinstance(t, objects.TableInstance):
7281
t = t.type
73-
assert t <= T.table
82+
83+
if not isinstance(t, (Type, objects.SelectedColumnInstance)):
84+
raise Signal.make(T.TypeError, type_, f"Expected type in column definition. Instead got '{t}'")
7485

7586
if type_.nullable:
7687
t = t.as_nullable()
@@ -207,7 +218,7 @@ def _execute(state: State, insert_rows: ast.InsertRows):
207218

208219
rval = evaluate(state, insert_rows.value)
209220

210-
assert_type(rval.type, T.table, state, insert_rows, '+=')
221+
assert_type(rval.type, T.table, insert_rows, '+=')
211222

212223
return _copy_rows(state, insert_rows.name, rval)
213224

@@ -602,7 +613,7 @@ def apply_database_rw(state: State, o: ast.One):
602613
return new_value_instance(row)
603614

604615
assert table.type <= T.table
605-
assert_type(table.type, T.table, state, o, 'one')
616+
assert_type(table.type, T.table, o, 'one')
606617
d = {k: new_value_instance(v, table.type.elems[k], True) for k, v in row.items()}
607618
return objects.RowInstance(rowtype, d)
608619

@@ -691,7 +702,7 @@ def apply_database_rw(state: State, new: ast.NewRows):
691702
# XXX Is it always TableInstance? Just sometimes? What's the transition here?
692703
obj = obj.type
693704

694-
assert_type(obj, T.table, state, new, "'new' expected an object of type '%s', instead got '%s'")
705+
assert_type(obj, T.table, new, "'new' expected an object of type '%s', instead got '%s'")
695706

696707
arg ,= new.args
697708

@@ -795,7 +806,7 @@ def create_exception(state, msg):
795806

796807
table = obj
797808
# TODO assert tabletype is a real table and not a query (not transient), otherwise new is meaningless
798-
assert_type(table.type, T.table, state, new, "'new' expected an object of type '%s', instead got '%s'")
809+
assert_type(table.type, T.table, new, "'new' expected an object of type '%s', instead got '%s'")
799810

800811
cons = TableConstructor.make(table.type)
801812
matched = cons.match_params(state, new.args)

preql/interp_common.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def get_var(self, name):
113113
except KeyError:
114114
pass
115115

116-
raise Signal.make(T.NameError, name, f"Name '{name}' not found")
116+
raise Signal.make(T.NameError, name, f"Name '{name}' is not defined")
117117

118118

119119
def set_var(self, name, value):
@@ -185,7 +185,7 @@ def get_all_vars_with_rank(self):
185185

186186

187187

188-
def assert_type(t, type_, state, ast_node, op, msg="%s expected an object of type %s, instead got '%s'"):
188+
def assert_type(t, type_, ast_node, op, msg="%s expected an object of type %s, instead got '%s'"):
189189
assert isinstance(t, Type), t
190190
assert isinstance(type_, Type)
191191
if not t <= type_:

preql/pql_ast.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ class One(Expr):
207207

208208
@dataclass
209209
class Type(Ast):
210-
name: Object
210+
type_obj: Object
211211
nullable: bool = False
212212

213213
class Definition:

preql/pql_functions.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,8 @@ def pql_issubclass(state: State, a: T.type, b: T.type):
219219
>> issubclass(list, table)
220220
true
221221
"""
222-
assert_type(a.type, T.type, state, a, 'issubclass')
223-
assert_type(b.type, T.type, state, b, 'issubclass')
222+
assert_type(a.type, T.type, a, 'issubclass')
223+
assert_type(b.type, T.type, b, 'issubclass')
224224
assert isinstance(a, Type)
225225
assert isinstance(b, Type)
226226
return new_value_instance(a <= b, T.bool)
@@ -238,7 +238,7 @@ def pql_isa(state: State, obj: T.any, type: T.type):
238238
>> isa([1], table)
239239
true
240240
"""
241-
assert_type(type.type, T.type, state, obj, 'isa')
241+
assert_type(type.type, T.type, obj, 'isa')
242242
res = obj.isa(type)
243243
return new_value_instance(res, T.bool)
244244

@@ -305,7 +305,7 @@ def pql_temptable(state: State, expr: T.table, const: T.bool.as_nullable() = obj
305305
# 'temptable' creates its own counting 'id' field. Copying existing 'id' fields will cause a collision
306306
# 'const table' doesn't
307307
const = cast_to_python(state, const)
308-
assert_type(expr.type, T.table, state, expr, 'temptable')
308+
assert_type(expr.type, T.table, expr, 'temptable')
309309

310310
name = state.unique_name("temp") # TODO get name from table options
311311

tests/test_basic.py

+3
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ def test_logical(self):
232232
assert preql('1 and 2 or 3') == 2
233233
assert preql('1 or 2 and 3') == 1
234234

235+
self.assertEqual( preql('[1] or [2]'), [1])
236+
self.assertEqual( preql('[1] and [2]'), [2])
237+
235238
def test_basic2(self):
236239
# More basic tests
237240
preql = self.Preql()

0 commit comments

Comments
 (0)