Closed bgrounds closed 2 years ago
You may want to try what I did for for the @effect.option
decorator. Instead of using @effect.option
which is typed as Any
, I imported the OptionBuilder
class and gave it the return type of the function it was decorating. So, using the example in the tutorial:
from expression import Nothing, Some
from expression.core.option import default_value
from expression.effect.option import OptionBuilder
@OptionBuilder[int]()
def fn():
x = yield from Nothing # or a function returning Nothing
# x = yield from Some(42) # or a function returning Nothing
print(x)
# -- The rest of the function will never be executed --
y = yield from Some(43)
print(y)
return x + y
xs = fn()
x = default_value(0)(xs)
y = default_value(0)(Some(43))
# assert xs is Nothing
z = x + y
print(f'at the end, z is {z}')
The extra variables and print statements were so I could understand the program flow and view the type information Pylance reported for the expressions.
Maybe using ResultBuilder
directly would also work as you need and keep the type information.
Note: I had to change the type returned by the Nothing.__iter__()
function in the expression.core.option.py
file in the expression library to:
def __iter__(self) -> Generator[TSource, TSource, TSource]:
to get Pylance to type yield from Nothing
correctly. I am going to report that... hopefully someone is taking care of this library... it looks like it took considerable work to create it.
I have made a PR #59 to have better typing of effects. This is a breaking change and you will need to call the decorator to set the type you need e.g:
@effect.result[int, Exception]()
def fn():
x: int = yield 42
y = yield from Ok(43)
return x + y
What do you think of this solution? Would this fix your problem?
I btw also added _try
so you can write:
@effect.try_[int]()
def fn():
x: int = yield 42
y = yield from Ok(43)
return x + y
NOTE: for this to work we need to drop support for Python 3.8
I've started plumbing the
Try
type throughout a program I'm working on for better error handling :)I just realized that the
@result
decorator drops type information (by returning aResultBuilder[Any, Any]
).I'm not sure if a decorator function could be written such that the type checker will infer the resulting (decorated) function's return type based on the input function's return type, which would be ideal. It seems like that should be possible, since the function-to-be-decorated (and its type annotation) will be available to the decorator function, but I haven't tried it.
But even if that's not possible, I'd rather pass type information around explicitly than drop it (via
Any
).By defining this
try_of
helper, I can (with a bit of boilerplate) recover the missing type information.Any thoughts? Is there an easier way to do this already?