66import ibis
77from ibis import Deferred
88from ibis .common .deferred import BinaryOperator , Resolver , Variable
9- from ibis .expr import types as ir
109
1110from mismo import _funcs , _util
1211
1312
1413@runtime_checkable
1514class ValueResolver (Protocol ):
16- """A callable, that given a Table, resolves to a single column ."""
15+ """A callable, that given a Table, resolves to a single Value ."""
1716
18- def __call__ (self , t : ibis .Table ) -> ibis .Column :
19- """Given a Table, resolve to a single column ."""
17+ def __call__ (self , t : ibis .Table ) -> ibis .Value :
18+ """Given a Table, resolve to a single Value ."""
2019
2120
2221class DeferredResolver (ValueResolver ):
@@ -30,7 +29,7 @@ def __init__(
3029 self .deferred = deferred
3130 self .name = name
3231
33- def __call__ (self , t : ibis .Table ) -> ibis .Column :
32+ def __call__ (self , t : ibis .Table ) -> ibis .Value :
3433 raw = self .deferred .resolve (** {self .name : t })
3534 return _util .bind_one (t , raw )
3635
@@ -44,17 +43,13 @@ def __str__(self) -> str:
4443
4544
4645class LiteralResolver (ValueResolver ):
46+ """A resolver that always returns the literal value given."""
47+
4748 def __init__ (self , value : ibis .Value ) -> None :
4849 self .value = value
4950
50- def __call__ (self , t : ibis .Table ) -> ibis .Column :
51- """Resolve a literal value."""
52- resolved = _util .bind (t , self .value )
53- if len (resolved ) != 1 :
54- raise ValueError (
55- f"Expected 1 column, got { len (resolved )} from { self .value } "
56- )
57- return resolved [0 ]
51+ def __call__ (self , t : ibis .Table ) -> ibis .Value :
52+ return _util .bind_one (t , self .value )
5853
5954 def __repr__ (self ) -> str :
6055 return f"LiteralResolver({ self .value !r} )"
@@ -84,11 +79,11 @@ def __str__(self):
8479class FuncResolver (ValueResolver ):
8580 def __init__ (
8681 self ,
87- func : Callable [[ibis .Table ], ibis .Column ],
82+ func : Callable [[ibis .Table ], ibis .Value ],
8883 ) -> None :
8984 self .func = func
9085
91- def __call__ (self , t : ibis .Table ) -> ibis .Column :
86+ def __call__ (self , t : ibis .Table ) -> ibis .Value :
9287 return self .func (t )
9388
9489 def __repr__ (self ):
@@ -164,7 +159,7 @@ def key_pair_resolvers(x) -> list[tuple[ValueResolver, ValueResolver]]:
164159 Given a spec or iterable of specs, return a list of KeyPairResolvers.
165160 """
166161 if (deferred_resolvers := _parse_and_of_equals (x )) is not None :
167- return deferred_resolvers
162+ return deferred_resolvers # ty:ignore[invalid-return-type]
168163 return [key_pair_resolver (spec ) for spec in _util .promote_list (x )]
169164
170165
@@ -174,7 +169,7 @@ def _parse_and_of_equals(x) -> list[tuple[DeferredResolver, DeferredResolver]] |
174169 return None
175170 if variables_names (x ) != {"left" , "right" }:
176171 return None
177- resolver = _resolver (x )
172+ resolver = _to_resolver (x )
178173 return list (_traverse_deferred_resolvers (resolver ))
179174
180175
@@ -218,13 +213,20 @@ def _traverse_deferred_resolvers(
218213 )
219214
220215
221- def _resolver (x : Any ) -> Resolver | None :
222- """Get the resolver from an object, if it has one."""
216+ @runtime_checkable
217+ class HasResolver (Protocol ):
218+ _resolver : Resolver
219+
220+
221+ def _to_resolver (x : Resolver | HasResolver | Deferred ) -> Resolver :
223222 if isinstance (x , Resolver ):
224223 return x
225- if hasattr (x , "_resolver" ):
224+ if isinstance (x , HasResolver ):
226225 return x ._resolver
227- return None
226+ raise TypeError (
227+ "Expected a Resolver or something with `_resolver`,"
228+ f" got { type (x ).__name__ } instead."
229+ )
228230
229231
230232def variables_names (deferred : Deferred | Resolver ) -> set [str ]:
@@ -252,7 +254,7 @@ def variables_names(deferred: Deferred | Resolver) -> set[str]:
252254 >>> sorted(variables_names(ibis._.foo + var("bar").baz.fill_null(8)))
253255 ['_', 'bar']
254256 """
255- resolver = _resolver (deferred )
257+ resolver = _to_resolver (deferred )
256258 if not isinstance (resolver , Resolver ):
257259 raise TypeError (
258260 f"Expected a Deferred or Resolver, got { type (deferred ).__name__ } instead."
0 commit comments