returns icon indicating copy to clipboard operation
returns copied to clipboard

Unit method like `IOResultE.from_value` must return `IOResult[_V, Exception]` type

Open sobolevn opened this issue 5 years ago • 9 comments

Currently, they do return incorrect types:

reveal_type(IOResultE.from_value(int))
# => IOResult[int, Any]

# Should be:
# => IOResult[int, Exception]

To achieve what we want we might tweak the way we create an alias in some way:

  1. We can use inheritance instead of aliasing
  2. We can use some magic
  3. mypy plugin?

sobolevn avatar Jun 06 '20 10:06 sobolevn

The same applies for all aliases with E suffix: ResultE, IOResultE, FutureResultE, ReaderResultE, etc

sobolevn avatar Jun 06 '20 11:06 sobolevn

Inheritance does not work:

class IOResultE(IOResult[_ValueType, Exception]):
    pass

reveal_type(IOResultE.from_value(42))  # N: Revealed type is 'returns.io.IOResult[builtins.int*, builtins.Exception*]'

Output:

main:6: note: Revealed type is 'returns.io.IOResult[builtins.int*, Any]'

thepabloaguilar avatar Jul 18 '20 23:07 thepabloaguilar

I got it, the actual signature is:

class IOResult:
    def from_value(cls, inner_value: _NewValueType) -> 'IOResult[_NewValueType, Any]':
        ...

I've just adjusted the return type to:

class IOResult:
    def from_value(cls, inner_value: _NewValueType) -> 'IOResult[_NewValueType, _ErrorType]':
        ...

Test case:

- case: test_io_result_e_from_value
  disable_cache: true
  main: |
    from returns.io import IOResultE

    reveal_type(IOResultE.from_value(10))  # N: Revealed type is 'returns.io.IOResult[builtins.int*, builtins.Exception]'

thepabloaguilar avatar Jul 19 '20 00:07 thepabloaguilar

@thepabloaguilar can you please test that these tests still work: https://github.com/dry-python/returns/blob/master/typesafety/test_io/test_ioresult_container/test_ioresult_typecast.yml ?

sobolevn avatar Jul 19 '20 07:07 sobolevn

Just one test was broken:

- case: ioresult_from_value
  disable_cache: true
  main: |
    from returns.io import IOResult

    reveal_type(IOResult.from_value(1))  # N: Revealed type is 'returns.io.IOResult[builtins.int*, Any]'

Output:

E   pytest_mypy_plugins.utils.TypecheckAssertionError: Invalid output: 
E   Expected:
E     main:3: note: Revealed type is 'returns.io.IOResult[builtins.int*, Any]' (diff)
E   Actual:
E     main:3: note: Revealed type is 'returns.io.IOResult[builtins.int*, <nothing>]' (diff)
E   
E   Alignment of first line difference:
E     E: ...io.IOResult[builtins.int*, Any]'
E     A: ...io.IOResult[builtins.int*, <nothing>]'

thepabloaguilar avatar Jul 19 '20 13:07 thepabloaguilar

I remember that we had problems with <nothing> somewhere. It does not compose with something.

Possible somewhere in:

  • #124
  • https://github.com/dry-python/returns/issues/196
  • https://github.com/dry-python/returns/issues/134
  • https://github.com/dry-python/returns/issues/140

sobolevn avatar Jul 19 '20 20:07 sobolevn

Ok, I found it: https://github.com/dry-python/returns/issues/124

sobolevn avatar Jul 19 '20 20:07 sobolevn

I am still not sure, why are we using Any?

sobolevn avatar Jul 19 '20 20:07 sobolevn

In fact we have this problem (Any) with IOSuccess and IOFailure too!

>>> reveal_type(IOSuccess(1))
# note: Revealed type is 'returns.io.IOResult[builtins.int*, Any]'

Unless we annotate the type explicit:

>>> io: IOResult[int, str] = IOSuccess(10)
>>> reveal_type(io)
# note: Revealed type is 'returns.io.IOResult[builtins.int*, builtins.str*]'

thepabloaguilar avatar Jul 19 '20 22:07 thepabloaguilar