First steps
Type system reference
Configuring and running mypy
Miscellaneous
Project Links
It is possible to integrate mypy into another Python 3 application byimportingmypy.api and calling therun function with a parameter of typelist[str], containingwhat normally would have been the command line arguments to mypy.
Functionrun returns atuple[str,str,int], namely(<normal_report>,<error_report>,<exit_status>), in which<normal_report>is what mypy normally writes tosys.stdout,<error_report> is what mypynormally writes tosys.stderr andexit_status is the exit status mypy normallyreturns to the operating system.
A trivial example of using the api is the following
importsysfrommypyimportapiresult=api.run(sys.argv[1:])ifresult[0]:print('\nType checking report:\n')print(result[0])# stdoutifresult[1]:print('\nError report:\n')print(result[1])# stderrprint('\nExit status:',result[2])
Python is a highly dynamic language and has extensive metaprogrammingcapabilities. Many popular libraries use these to create APIs that maybe more flexible and/or natural for humans, but are hard to express usingstatic types. Extending thePEP 484 type system to accommodate all existingdynamic patterns is impractical and often just impossible.
Mypy supports a plugin system that lets you customize the way mypy type checkscode. This can be useful if you want to extend mypy so it can type check codethat uses a library that is difficult to express using justPEP 484 types.
The plugin system is focused on improving mypy’s understandingofsemantics of third party frameworks. There is currently no way to definenew first class kinds of types.
Note
The plugin system is experimental and prone to change. If you want to writea mypy plugin, we recommend you start by contacting the mypy core developersongitter. In particular, there areno guarantees about backwards compatibility.
Backwards incompatible changes may be made without a deprecation period,but we will announce them inthe plugin API changes announcement issue.
Plugins are Python files that can be specified in a mypyconfig file using theplugins option and one of the two formats: relative orabsolute path to the plugin file, or a module name (if the pluginis installed usingpipinstall in the same virtual environment where mypyis running). The two formats can be mixed, for example:
[mypy]plugins=/one/plugin.py, other.plugin
Mypy will try to import the plugins and will look for an entry point functionnamedplugin. If the plugin entry point function has a different name, itcan be specified after colon:
[mypy]plugins=custom_plugin:custom_entry_point
In the following sections we describe the basics of the plugin system withsome examples. For more technical details, please read the docstrings inmypy/plugin.pyin mypy source code. Also you can find good examples in the bundled pluginslocated inmypy/plugins.
Every entry point function should accept a single string argumentthat is a full mypy version and return a subclass ofmypy.plugin.Plugin:
frommypy.pluginimportPluginclassCustomPlugin(Plugin):defget_type_analyze_hook(self,fullname:str):# see explanation below...defplugin(version:str):# ignore version argument if the plugin works with all mypy versions.returnCustomPlugin
During different phases of analyzing the code (first in semantic analysis,and then in type checking) mypy calls plugin methods such asget_type_analyze_hook() on user plugins. This particular method, for example,can return a callback that mypy will use to analyze unbound types with the givenfull name. See the full plugin hook method listbelow.
Mypy maintains a list of plugins it gets from the config file plus the default(built-in) plugin that is always enabled. Mypy calls a method once for eachplugin in the list until one of the methods returns a non-None value.This callback will be then used to customize the corresponding aspect ofanalyzing/checking the current abstract syntax tree node.
The callback returned by theget_xxx method will be given a detailedcurrent context and an API to create new nodes, new types, emit error messages,etc., and the result will be used for further processing.
Plugin developers should ensure that their plugins work well in incremental anddaemon modes. In particular, plugins should not hold global state due to cachingof plugin hook results.
get_type_analyze_hook() customizes behaviour of the type analyzer.For example,PEP 484 doesn’t support defining variadic generic types:
fromlibimportVectora:Vector[int,int]b:Vector[int,int,int]
When analyzing this code, mypy will callget_type_analyze_hook("lib.Vector"),so the plugin can return some valid type for each variable.
get_function_hook() is used to adjust the return type of a function call.This hook will be also called for instantiation of classes.This is a good choice if the return type is too complexto be expressed by regular python typing.
get_function_signature_hook() is used to adjust the signature of a function.
get_method_hook() is the same asget_function_hook() but for methodsinstead of module level functions.
get_method_signature_hook() is used to adjust the signature of a method.This includes special Python methods except__init__() and__new__().For example in this code:
fromctypesimportArray,c_intx:Array[c_int]x[0]=42
mypy will callget_method_signature_hook("ctypes.Array.__setitem__")so that the plugin can mimic thectypes auto-convert behavior.
get_attribute_hook() overrides instance member field lookups and propertyaccess (not method calls). This hook is only called forfields which already exist on the class.Exception: if__getattr__ or__getattribute__ is a method on the class, the hook is called for allfields which do not refer to methods.
get_class_attribute_hook() is similar to above, but for attributes on classes rather than instances.Unlike above, this does not have special casing for__getattr__ or__getattribute__.
get_class_decorator_hook() can be used to update class definition forgiven class decorators. For example, you can add some attributes to the classto match runtime behaviour:
fromdataclassesimportdataclass@dataclass# built-in plugin adds `__init__` method hereclassUser:name:struser=User(name='example')# mypy can understand this using a plugin
get_metaclass_hook() is similar to above, but for metaclasses.
get_base_class_hook() is similar to above, but for base classes.
get_dynamic_class_hook() can be used to allow dynamic class definitionsin mypy. This plugin hook is called for every assignment to a simple namewhere right hand side is a function call:
fromlibimportdynamic_classX=dynamic_class('X',[])
For such definition, mypy will callget_dynamic_class_hook("lib.dynamic_class").The plugin should create the correspondingmypy.nodes.TypeInfo object, andplace it into a relevant symbol table. (Instances of this class representclasses in mypy and hold essential information such as qualified name,method resolution order, etc.)
get_customize_class_mro_hook() can be used to modify class MRO (for exampleinsert some entries there) before the class body is analyzed.
get_additional_deps() can be used to add new dependencies for amodule. It is called before semantic analysis. For example, this canbe used if a library has dependencies that are dynamically loadedbased on configuration information.
report_config_data() can be used if the plugin has some sort ofper-module configuration that can affect typechecking. In that case,when the configuration for a module changes, we want to invalidatemypy’s cache for that module so that it can be rechecked. This hookshould be used to report to mypy any relevant configuration data,so that mypy knows to recheck the module if the configuration changes.The hooks should return data encodable as JSON.
Mypy shipsmypy.plugins.proper_plugin plugin which can be usefulfor plugin authors, since it finds missingget_proper_type() calls,which is a pretty common mistake.
It is recommended to enable it as a part of your plugin’s CI.