We provide a custom mypy
plugin to fix existing issues,
provide new awesome features,
and improve type-safety of things developers commonly use.
You will need to install mypy
separately.
It is not bundled with returns
.
To install any mypy
plugin add it
to the plugins
section of the config file.
[mypy]
plugins =
returns.contrib.mypy.returns_plugin
We recommend to always add our plugin as the first one in chain.
You can have a look at the suggested mypy
configuration
in our own repository.
You can also use nitpick
tool to enforce the same mypy
configuration for all your projects.
We recommend to use our own setup. Add this to your pyproject.toml
:
[tool.nitpick]
style = "https://raw.githubusercontent.com/wemake-services/wemake-python-styleguide/master/styles/mypy.toml"
And use flake8
to lint that configuration
defined in the setup matches yours.
This will allow to keep them in sync with the upstream.
kind
feature adds Higher Kinded Types (HKT) support
curry
feature allows to write typed curried functions
partial
feature allows to write typed partial application
flow
feature allows to write better typed functional pipelines
with flow
function
pipe
feature allows to write better typed functional pipelines
with pipe
function
Used for typed partial
function.
Used for typed curry
decorator.
Used for typed flow
call.
Used for typed pipe
call.
Used for HKT emulation.
Custom mypy plugin to solve the temporary problem with python typing.
Important: we don’t do anything ugly here. We only solve problems of the current typing implementation.
mypy
API docs are here:
https://mypy.readthedocs.io/en/latest/extending_mypy.html
We use pytest-mypy-plugins
to test that it works correctly, see:
https://github.com/mkurnikov/pytest-mypy-plugins
Ensures that attribute access to KindN
is correct.
In other words:
from typing import TypeVar
from returns.primitives.hkt import KindN
from returns.interfaces.mappable import MappableN
_MappableType = TypeVar('_MappableType', bound=MappableN)
kind: KindN[_MappableType, int, int, int]
reveal_type(kind.map) # will work correctly!
ctx (AttributeContext
) –
Type
Infers real type behind Kind
form.
Basically, it turns Kind[IO, int]
into IO[int]
.
The only limitation is that it works with
only Instance
type in the first type argument position.
So, dekind(KindN[T, int])
will fail.
ctx (FunctionContext
) –
Type
Returns the internal function wrapped as Kinded[def]
.
Works for Kinded
class when __call__
magic method is used.
See returns.primitives.hkt.Kinded
for more information.
ctx (MethodSigContext
) –
CallableType
Reveals the correct return type of Kinded.__call__
method.
Turns -> KindN[I, t1, t2, t3]
into -> I[t1, t2, t3]
.
Also strips unused type arguments for KindN
, so:
- KindN[IO, int, <nothing>, <nothing>]
will be IO[int]
- KindN[Result, int, str, <nothing>]
will be Result[int, str]
It also processes nested KindN
with recursive strategy.
See returns.primitives.hkt.Kinded
for more information.
ctx (MethodContext
) –
Type
This hook is used to make typed curring a thing in returns project.
This plugin is a temporary solution to the problem.
It should be later replaced with the official way of doing things.
One day functions will have better API and we plan
to submit this plugin into mypy
core plugins,
so it would not be required.
Internally we just reduce the original function’s argument count. And drop some of them from function’s signature.
ctx (FunctionContext
) –
Type
Helps to analyze flow
function calls.
By default, mypy
cannot infer and check this function call:
>>> from returns.pipeline import flow
>>> assert flow(
... 1,
... lambda x: x + 1,
... lambda y: y / 2,
... ) == 1.0
But, this plugin can!
It knows all the types for all lambda
functions in the pipeline.
How?
We use the first passed parameter as the first argument to the first passed function
We use parameter + function to check the call and reveal types of current pipeline step
We iterate through all passed function and use previous return type as a new parameter to call current function
ctx (FunctionContext
) –
Type
Typing pipe
functions requires several phases.
It is pretty obvious from its usage:
When we pass a sequence of functions we have to reduce
the final callable type, it is require to match the callable
protocol.
And at this point we also kinda try
to check that all pipeline functions do match,
but this is impossible to do 100% correctly at this point,
because generic functions don’t have a type argument
to infer the final result
When we call the function, we need to check for two things. First, we check that passed argument fits our instance requirement. Second, we check that pipeline functions match. Now we have all arguments to do the real inference.
We also need to fix generic in method signature. It might be broken, because we add new generic arguments and return type. So, it is safe to reattach generic back to the function.
Here’s when it works:
>>> from returns.pipeline import pipe
>>> def first(arg: int) -> bool:
... return arg > 0
>>> def second(arg: bool) -> str:
... return 'bigger' if arg else 'not bigger'
>>> pipeline = pipe(first, second) # `analyzed` is called
>>> assert pipeline(1) == 'bigger' # `signature and `infer` are called
>>> assert pipeline(0) == 'not bigger' # `signature and `infer` again
This hook helps when we create the pipeline from sequence of funcs.
ctx (FunctionContext
) –
Type