Skip to content

Commit 35007eb

Browse files
committed
Refactored Signal.make to use context
1 parent b955619 commit 35007eb

12 files changed

+149
-137
lines changed

preql/api.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,7 @@ def _wrap_result(self, res):
139139

140140
def _run_code(self, pq: str, source_file: str, **args):
141141
pql_args = {name: objects.from_python(value) for name, value in args.items()}
142-
try:
143-
return self.interp.execute_code(pq + "\n", source_file, pql_args)
144-
except exc.ReturnSignal:
145-
raise Signal.make(T.CodeError, self.interp.state, None, "'return' outside of function")
142+
return self.interp.execute_code(pq + "\n", source_file, pql_args)
146143

147144
def __call__(self, pq, **args):
148145
res = self._run_code(pq, '<inline>', **args)

preql/autocomplete.py

+15-15
Original file line numberDiff line numberDiff line change
@@ -170,19 +170,19 @@ def _eval_autocomplete(ac_state, stmts):
170170

171171
def autocomplete(state, code, source='<autocomplete>'):
172172
ac_state = AcState.clone(state)
173-
try:
174-
stmts = parser.parse_stmts(code, source, wrap_syntax_error=False)
175-
except UnexpectedCharacters as e:
176-
return {}
177-
except UnexpectedToken as e:
178-
tree = autocomplete_tree(e.puppet)
179-
if tree:
180-
try:
181-
stmts = parser.TreeToAst(code_ref=(code, source)).transform(tree)
182-
except pql_SyntaxError as e:
183-
return {}
184-
185-
with context(state=ac_state):
173+
with context(state=ac_state):
174+
try:
175+
stmts = parser.parse_stmts(code, source, wrap_syntax_error=False)
176+
except UnexpectedCharacters as e:
177+
return {}
178+
except UnexpectedToken as e:
179+
tree = autocomplete_tree(e.puppet)
180+
if tree:
181+
try:
182+
stmts = parser.TreeToAst(code_ref=(code, source)).transform(tree)
183+
except pql_SyntaxError as e:
184+
return {}
185+
186186
_eval_autocomplete(ac_state, stmts[:-1])
187187

188188
try:
@@ -193,7 +193,7 @@ def autocomplete(state, code, source='<autocomplete>'):
193193
except Signal as e:
194194
ac_log.exception(e)
195195

196-
else:
197-
_eval_autocomplete(ac_state, stmts)
196+
else:
197+
_eval_autocomplete(ac_state, stmts)
198198

199199
return ac_state.get_all_vars_with_rank()

preql/casts.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
def _cast(state, inst_type, target_type, inst):
88
if inst_type == target_type or target_type is T.any:
99
return inst
10-
raise Signal.make(T.TypeError, state, None, f"Cast not implemented for {inst_type}->{target_type}")
10+
raise Signal.make(T.TypeError, None, f"Cast not implemented for {inst_type}->{target_type}")
1111

1212
@dp_type
1313
def _cast(state, inst_type: T.list, target_type: T.list, inst):
@@ -32,9 +32,9 @@ def _cast(state, inst_type: T.aggregate, target_type: T.list, inst):
3232
def _cast(state, inst_type: T.table, target_type: T.list, inst):
3333
t = inst.type
3434
if len(t.elems) != 1:
35-
raise Signal.make(T.TypeError, state, None, f"Cannot cast {inst_type} to {target_type}. Too many columns")
35+
raise Signal.make(T.TypeError, None, f"Cannot cast {inst_type} to {target_type}. Too many columns")
3636
if not (inst_type.elem <= target_type.elem):
37-
raise Signal.make(T.TypeError, state, None, f"Cannot cast {inst_type} to {target_type}. Elements not matching")
37+
raise Signal.make(T.TypeError, None, f"Cannot cast {inst_type} to {target_type}. Elements not matching")
3838

3939
(elem_name, elem_type) ,= inst_type.elems.items()
4040
code = sql.Select(T.list[elem_type], inst.code, [sql.ColumnAlias(sql.Name(elem_type, elem_name), ITEM_NAME)])

preql/compiler.py

+39-39
Large diffs are not rendered by default.

preql/context.py

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ def __getattr__(self, name):
1212

1313
raise AttributeError(name)
1414

15+
def get(self, name, default=None):
16+
try:
17+
return getattr(self, name)
18+
except AttributeError:
19+
return default
20+
1521
@contextmanager
1622
def __call__(self, **attrs):
1723
self._ctx.append(attrs)

preql/evaluate.py

+31-31
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def db_query(state: State, sql_code, subqueries=None):
8686
try:
8787
return state.db.query(sql_code, subqueries, state=state)
8888
except exc.DatabaseQueryError as e:
89-
raise Signal.make(T.DbQueryError, state, None, e.args[0]) from e
89+
raise Signal.make(T.DbQueryError, None, e.args[0]) from e
9090

9191
def drop_table(state, table_type):
9292
name ,= table_type.options['name'].parts
@@ -115,7 +115,7 @@ def _execute(state: State, table_def: ast.TableDef):
115115

116116
if any(isinstance(c, ast.Ellipsis) for c in table_def.columns):
117117
# XXX why must it? just ensure it appears once
118-
raise Signal.make(T.SyntaxError, state, table_def, "Ellipsis must appear at the end")
118+
raise Signal.make(T.SyntaxError, table_def, "Ellipsis must appear at the end")
119119

120120
# Create type and a corresponding table in the database
121121
t = resolve(state, table_def)
@@ -140,12 +140,12 @@ def _execute(state: State, table_def: ast.TableDef):
140140
for e_name, e1_type in t.elems.items():
141141

142142
if e_name not in cur_type.elems:
143-
raise Signal.make(T.TypeError, state, table_def, f"Column '{e_name}' defined, but doesn't exist in database.")
143+
raise Signal.make(T.TypeError, table_def, f"Column '{e_name}' defined, but doesn't exist in database.")
144144

145145
e2_type = cur_type.elems[e_name]
146146
# XXX use can_cast() instead of hardcoding it
147147
# if not (e1_type <= e2_type or (e1_type <= T.t_id and e2_type <= T.int)):
148-
# raise Signal.make(T.TypeError, state, table_def, f"Cannot cast column '{e_name}' from type '{e2_type}' to '{e1_type}'")
148+
# raise Signal.make(T.TypeError, table_def, f"Cannot cast column '{e_name}' from type '{e2_type}' to '{e1_type}'")
149149

150150
inst = objects.new_table(t, db_name, select_fields=True)
151151
else:
@@ -168,7 +168,7 @@ def _set_value(state: State, name: ast.Name, value):
168168

169169
@dy
170170
def _set_value(state: State, attr: ast.Attr, value):
171-
raise Signal.make(T.NotImplementedError, state, attr, f"Cannot set attribute for {attr.expr.repr(state)}")
171+
raise Signal.make(T.NotImplementedError, attr, f"Cannot set attribute for {attr.expr.repr(state)}")
172172

173173
@dy
174174
def _execute(state: State, var_def: ast.SetValue):
@@ -188,7 +188,7 @@ def _copy_rows(state: State, target_name: ast.Name, source: objects.TableInstanc
188188
params = dict(table_params(target.type))
189189
for p in params:
190190
if p not in source.type.elems:
191-
raise Signal.make(T.TypeError, state, source, f"Missing column '{p}' in {source.type}")
191+
raise Signal.make(T.TypeError, source, f"Missing column '{p}' in {source.type}")
192192

193193
primary_keys, columns = table_flat_for_insert(target.type)
194194

@@ -249,7 +249,7 @@ def _execute(state: State, p: ast.Assert):
249249
s = (' %s '%p.cond.op).join(str(evaluate(state, a).repr(state)) for a in p.cond.args)
250250
else:
251251
s = p.cond.repr(state)
252-
raise Signal.make(T.AssertError, state, p.cond, f"Assertion failed: {s}")
252+
raise Signal.make(T.AssertError, p.cond, f"Assertion failed: {s}")
253253

254254
@dy
255255
def _execute(state: State, cb: ast.CodeBlock):
@@ -297,7 +297,7 @@ def import_module(state, r):
297297
if module_path.exists():
298298
break
299299
else:
300-
raise Signal.make(T.ImportError, state, r, "Cannot find module")
300+
raise Signal.make(T.ImportError, r, "Cannot find module")
301301

302302
from .interpreter import Interpreter # XXX state.new_interp() ?
303303
i = Interpreter(state.db, state.fmt, use_core=r.use_core)
@@ -415,7 +415,7 @@ def simplify(state: State, obj: ast.Or):
415415
a, b = evaluate(state, obj.args)
416416
_, (ta, tb) = objects.unvectorize_args([a,b])
417417
if ta.type != tb.type:
418-
raise Signal.make(T.TypeError, state, obj, f"'or' operator requires both arguments to be of the same type, but got '{ta.type}' and '{tb.type}'.")
418+
raise Signal.make(T.TypeError, obj, f"'or' operator requires both arguments to be of the same type, but got '{ta.type}' and '{tb.type}'.")
419419
try:
420420
if test_nonzero(state, a):
421421
return a
@@ -429,7 +429,7 @@ def simplify(state: State, obj: ast.And):
429429
a, b = evaluate(state, obj.args)
430430
_, (ta, tb) = objects.unvectorize_args([a,b])
431431
if ta.type != tb.type:
432-
raise Signal.make(T.TypeError, state, obj, f"'or' operator requires both arguments to be of the same type, but got '{ta.type}' and '{tb.type}'.")
432+
raise Signal.make(T.TypeError, obj, f"'or' operator requires both arguments to be of the same type, but got '{ta.type}' and '{tb.type}'.")
433433
try:
434434
if not test_nonzero(state, a):
435435
return a
@@ -455,7 +455,7 @@ def simplify(state: State, funccall: ast.FuncCall):
455455

456456
if isinstance(func, objects.UnknownInstance):
457457
# evaluate(state, [a.value for a in funccall.args])
458-
raise Signal.make(T.TypeError, state, funccall.func, f"Error: Object of type '{func.type}' is not callable")
458+
raise Signal.make(T.TypeError, funccall.func, f"Error: Object of type '{func.type}' is not callable")
459459

460460
args = funccall.args
461461
if isinstance(func, Type):
@@ -464,7 +464,7 @@ def simplify(state: State, funccall: ast.FuncCall):
464464
func = state.get_var('cast')
465465

466466
if not isinstance(func, objects.Function):
467-
raise Signal.make(T.TypeError, state, funccall.func, f"Error: Object of type '{func.type}' is not callable")
467+
raise Signal.make(T.TypeError, funccall.func, f"Error: Object of type '{func.type}' is not callable")
468468

469469
state.stacktrace.append(funccall.text_ref)
470470
try:
@@ -497,7 +497,7 @@ def eval_func_call(state, func, args):
497497
# TODO cast?
498498
# if p.type and not a.type <= T.union[p.type, T.vectorized[p.type]]:
499499
if p.type and not a.type <= p.type:
500-
raise Signal.make(T.TypeError, state, func, f"Argument #{i} of '{func.name}' is of type '{a.type}', expected '{p.type}'")
500+
raise Signal.make(T.TypeError, func, f"Argument #{i} of '{func.name}' is of type '{a.type}', expected '{p.type}'")
501501
args[p.name] = a
502502

503503

@@ -583,7 +583,7 @@ def apply_database_rw(state: State, o: ast.One):
583583
obj = evaluate(state, o.expr)
584584
if obj.type <= T.struct:
585585
if len(obj.attrs) != 1:
586-
raise Signal.make(T.ValueError, state, o, f"'one' expected a struct with a single attribute, got {len(obj.attrs)}")
586+
raise Signal.make(T.ValueError, o, f"'one' expected a struct with a single attribute, got {len(obj.attrs)}")
587587
x ,= obj.attrs.values()
588588
return x
589589

@@ -594,10 +594,10 @@ def apply_database_rw(state: State, o: ast.One):
594594
rows = localize(state, table) # Must be 1 row
595595
if len(rows) == 0:
596596
if not o.nullable:
597-
raise Signal.make(T.ValueError, state, o, "'one' expected a single result, got an empty expression")
597+
raise Signal.make(T.ValueError, o, "'one' expected a single result, got an empty expression")
598598
return objects.null
599599
elif len(rows) > 1:
600-
raise Signal.make(T.ValueError, state, o, "'one' expected a single result, got more")
600+
raise Signal.make(T.ValueError, o, "'one' expected a single result, got more")
601601

602602
row ,= rows
603603
rowtype = T.row[table.type]
@@ -620,15 +620,15 @@ def apply_database_rw(state: State, d: ast.Delete):
620620
table = evaluate(state, cond_table)
621621

622622
if not (table.type <= T.table):
623-
raise Signal.make(T.TypeError, state, d.table, f"Expected a table. Got: {table.type}")
623+
raise Signal.make(T.TypeError, d.table, f"Expected a table. Got: {table.type}")
624624

625625
if not 'name' in table.type.options:
626-
raise Signal.make(T.ValueError, state, d.table, "Cannot delete. Table is not persistent")
626+
raise Signal.make(T.ValueError, d.table, "Cannot delete. Table is not persistent")
627627

628628
rows = list(localize(state, table))
629629
if rows:
630630
if 'id' not in rows[0]:
631-
raise Signal.make(T.TypeError, state, d, "Delete error: Table does not contain id")
631+
raise Signal.make(T.TypeError, d, "Delete error: Table does not contain id")
632632

633633
ids = [row['id'] for row in rows]
634634

@@ -645,14 +645,14 @@ def apply_database_rw(state: State, u: ast.Update):
645645
table = evaluate(state, u.table)
646646

647647
if not (table.type <= T.table):
648-
raise Signal.make(T.TypeError, state, u.table, f"Expected a table. Got: {table.type}")
648+
raise Signal.make(T.TypeError, u.table, f"Expected a table. Got: {table.type}")
649649

650650
if not 'name' in table.type.options:
651-
raise Signal.make(T.ValueError, state, u.table, "Cannot update: Table is not persistent")
651+
raise Signal.make(T.ValueError, u.table, "Cannot update: Table is not persistent")
652652

653653
for f in u.fields:
654654
if not f.name:
655-
raise Signal.make(T.SyntaxError, state, f, f"Update requires that all fields have a name")
655+
raise Signal.make(T.SyntaxError, f, f"Update requires that all fields have a name")
656656

657657
# TODO verify table is concrete (i.e. lvalue, not a transitory expression)
658658

@@ -663,9 +663,9 @@ def apply_database_rw(state: State, u: ast.Update):
663663
rows = list(localize(state, table))
664664
if rows:
665665
if 'id' not in rows[0]:
666-
raise Signal.make(T.TypeError, state, u, "Update error: Table does not contain id")
666+
raise Signal.make(T.TypeError, u, "Update error: Table does not contain id")
667667
if not set(proj) < set(rows[0]):
668-
raise Signal.make(T.TypeError, state, u, "Update error: Not all keys exist in table")
668+
raise Signal.make(T.TypeError, u, "Update error: Not all keys exist in table")
669669

670670
ids = [row['id'] for row in rows]
671671

@@ -683,7 +683,7 @@ def apply_database_rw(state: State, new: ast.NewRows):
683683
obj = state.get_var(new.type)
684684

685685
if len(new.args) > 1:
686-
raise Signal.make(T.NotImplementedError, state, new, "Not yet implemented") #. Requires column-wise table concat (use join and enum)")
686+
raise Signal.make(T.NotImplementedError, new, "Not yet implemented") #. Requires column-wise table concat (use join and enum)")
687687

688688
if isinstance(obj, objects.UnknownInstance):
689689
arg ,= new.args
@@ -728,9 +728,9 @@ def _destructure_param_match(state, ast_node, param_match):
728728
if (k.type <= T.struct):
729729
names = [name for name, t in flatten_type(k.orig, [k.name])]
730730
if not isinstance(v, list):
731-
raise Signal.make(T.TypeError, state, ast_node, f"Parameter {k.name} received a bad value: {v} (expecting a struct or a list)")
731+
raise Signal.make(T.TypeError, ast_node, f"Parameter {k.name} received a bad value: {v} (expecting a struct or a list)")
732732
if len(v) != len(names):
733-
raise Signal.make(T.TypeError, state, ast_node, f"Parameter {k.name} received a bad value (size of {len(names)})")
733+
raise Signal.make(T.TypeError, ast_node, f"Parameter {k.name} received a bad value (size of {len(names)})")
734734
yield from safezip(names, v)
735735
else:
736736
yield k.name, v
@@ -784,7 +784,7 @@ def create_exception(state, msg):
784784
return res
785785

786786
if not isinstance(obj, objects.TableInstance):
787-
raise Signal.make(T.TypeError, state, new, f"'new' expects a table or exception, instead got {obj.repr(state)}")
787+
raise Signal.make(T.TypeError, new, f"'new' expects a table or exception, instead got {obj.repr(state)}")
788788

789789
table = obj
790790
# TODO assert tabletype is a real table and not a query (not transient), otherwise new is meaningless
@@ -969,7 +969,7 @@ def new_table_from_expr(state, name, expr, const, temporary):
969969
return objects.TableInstance.make(sql.null, expr.type, [])
970970

971971
if 'id' in elems and not const:
972-
raise Signal.make(T.NameError, state, None, "Field 'id' already exists. Rename it, or use 'const table' to copy it as-is.")
972+
raise Signal.make(T.NameError, None, "Field 'id' already exists. Rename it, or use 'const table' to copy it as-is.")
973973

974974
table = T.table(dict(elems), name=Id(name), pk=[] if const else [['id']], temporary=temporary)
975975

@@ -987,7 +987,7 @@ def new_table_from_expr(state, name, expr, const, temporary):
987987

988988
@dy
989989
def cast_to_python(state, obj):
990-
raise Signal.make(T.TypeError, state, None, f"Unexpected value: {pql_repr(state, obj.type, obj)}")
990+
raise Signal.make(T.TypeError, None, f"Unexpected value: {pql_repr(state, obj.type, obj)}")
991991

992992
@dy
993993
def cast_to_python(state, obj: ast.Ast):
@@ -999,7 +999,7 @@ def cast_to_python(state, obj: objects.AbsInstance):
999999
# if state.access_level <= state.AccessLevels.QUERY:
10001000
if obj.type <= T.vectorized:
10011001
raise exc.InsufficientAccessLevel(state.access_level)
1002-
# raise Signal.make(T.CastError, state, None, f"Internal error. Cannot cast vectorized (i.e. projected) obj: {obj}")
1002+
# raise Signal.make(T.CastError, None, f"Internal error. Cannot cast vectorized (i.e. projected) obj: {obj}")
10031003
res = localize(state, obj)
10041004
if obj.type == T.float:
10051005
res = float(res)

preql/exceptions.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,21 @@
55
from .utils import dataclass, TextReference
66
from .base import Object
77

8+
from .context import context
9+
810
@dataclass
911
class Signal(Object, Exception):
1012
type: object # Type
1113
text_refs: List[Optional[TextReference]] # XXX must it be optional?
1214
message: Optional[str]
1315

1416
@classmethod
15-
def make(cls, type, state, ast, message):
17+
def make(cls, type, ast, message):
1618
ast_ref = getattr(ast, 'text_ref', None)
17-
refs = state.stacktrace+([ast_ref] if ast_ref else [])
19+
try:
20+
refs = context.state.stacktrace+([ast_ref] if ast_ref else [])
21+
except AttributeError:
22+
refs = []
1823
return cls(type, refs, message)
1924

2025
# def __str__(self):

preql/interp_common.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,11 @@ def connect(self, uri, auto_create=False):
8989
try:
9090
self.db = create_engine(uri, self.db._print_sql, auto_create)
9191
except NotImplementedError as e:
92-
raise Signal.make(T.NotImplementedError, self, None, *e.args) from e
92+
raise Signal.make(T.NotImplementedError, None, *e.args) from e
9393
except ConnectError as e:
94-
raise Signal.make(T.DbConnectionError, self, None, *e.args) from e
94+
raise Signal.make(T.DbConnectionError, None, *e.args) from e
9595
except ValueError as e:
96-
raise Signal.make(T.ValueError, self, None, *e.args) from e
96+
raise Signal.make(T.ValueError, None, *e.args) from e
9797

9898
self._db_uri = uri
9999

@@ -115,7 +115,7 @@ def get_var(self, name):
115115
except KeyError:
116116
pass
117117

118-
raise Signal.make(T.NameError, self, name, f"Name '{name}' not found")
118+
raise Signal.make(T.NameError, name, f"Name '{name}' not found")
119119

120120

121121
def set_var(self, name, value):

0 commit comments

Comments
 (0)