This package is available on PyPI
pip install pytest-mypy-pluginsand conda-forge
conda install -c conda-forge pytest-mypy-pluginsPlugin, after installation, is automatically picked up by pytest therefore it is sufficient to
just execute:
pytestThe PYTHONPATH and MYPYPATH environment variables, if set, are passed to mypy on invocation.
This may be helpful if you are testing a local plugin and need to provide an import path to it.
Be aware that when mypy is run in a subprocess (the default) the test cases are run in temporary working directories
where relative paths such as PYTHONPATH=./my_plugin do not reference the directory which you are running pytest from.
If you encounter this, consider invoking pytest with --mypy-same-process or make your paths absolute,
e.g. PYTHONPATH=$(pwd)/my_plugin pytest.
You can also specify PYTHONPATH, MYPYPATH, or any other environment variable in env: section of yml spec:
- case: mypy_path_from_env
  main: |
    from pair import Pair
    instance: Pair
    reveal_type(instance)  # N: Revealed type is 'pair.Pair'
  env:
    - MYPYPATH=../fixturesIn general each test case is just an element in an array written in a properly formatted YAML file.
On top of that, each case must comply to following types:
| Property | Type | Description | 
|---|---|---|
| case | str | Name of the test case, complies to [a-zA-Z0-9]pattern | 
| main | str | Portion of the code as if written in .pyfile | 
| files | Optional[List[File]]=[]* | List of extra files to simulate imports if needed | 
| disable_cache | Optional[bool]=False | Set to truedisablesmypycaching | 
| mypy_config | Optional[str] | Inline mypyconfiguration, passed directly tomypyas--config-fileoption, possibly joined with--mypy-pyproject-toml-fileor--mypy-ini-filecontents if they are passed. By default is treated asini, treated astomlonly if--mypy-pyproject-toml-fileis passed | 
| env | Optional[Dict[str, str]]={} | Environmental variables to be provided inside of test run | 
| parametrized | Optional[List[Parameter]]=[]* | List of parameters, similar to @pytest.mark.parametrize | 
| skip | str | Expression evaluated with following globals set: sys,os,pytestandplatform | 
| expect_fail | bool | Mark test case as an expected failure, like @pytest.mark.xfail | 
| regex | str | Allow regular expressions in comments to be matched against actual output. Defaults to "no", i.e. matches full text. | 
(*) Appendix to pseudo types used above:
class File:
    path: str
    content: Optional[str] = None
Parameter = Mapping[str, Any]Implementation notes:
- mainmust be non-empty string that evaluates to valid Python code,
- contentof each of extra files must evaluate to valid Python code,
- parametrizedentries must all be the objects of the same type. It simply means that each entry must have exact same set of keys,
- skip- an expression set in- skipis passed directly into- eval. It is advised to take a peek and learn about how- evalworks.
Repository also offers a JSONSchema, with which it validates the input. It can also offer your editor auto-completions, descriptions, and validation.
All you have to do, add the following line at the top of your YAML file:
# yaml-language-server: $schema=https://raw.githubusercontent.com/typeddjango/pytest-mypy-plugins/master/pytest_mypy_plugins/schema.json# typesafety/test_request.yml
- case: request_object_has_user_of_type_auth_user_model
  main: |
    from django.http.request import HttpRequest
    reveal_type(HttpRequest().user)  # N: Revealed type is 'myapp.models.MyUser'
    # check that other fields work ok
    reveal_type(HttpRequest().method)  # N: Revealed type is 'Union[builtins.str, None]'
  files:
    - path: myapp/__init__.py
    - path: myapp/models.py
      content: |
        from django.db import models
        class MyUser(models.Model):
            pass- case: with_params
  parametrized:
    - val: 1
      rt: builtins.int
    - val: 1.0
      rt: builtins.float
  main: |
    reveal_type({{ val }})  # N: Revealed type is '{{ rt }}'Properties that you can parametrize:
- main
- mypy_config
- out
- case: with_out
  main: |
    reveal_type('abc')
  out: |
    main:1: note: Revealed type is 'builtins.str'- case: expected_message_regex_with_out
  regex: yes
  main: |
    a = 'abc'
    reveal_type(a)
  out: |
    main:2: note: .*str.*- case: expected_single_message_regex
  main: |
    a = 'hello'
    reveal_type(a)  # NR: .*str.*mypy-tests:
  --mypy-testing-base=MYPY_TESTING_BASE
                        Base directory for tests to use
  --mypy-pyproject-toml-file=MYPY_PYPROJECT_TOML_FILE
                        Which `pyproject.toml` file to use
                        as a default config for tests.
                        Incompatible with `--mypy-ini-file`
  --mypy-ini-file=MYPY_INI_FILE
                        Which `.ini` file to use as a default config for tests.
                        Incompatible with `--mypy-pyproject-toml-file`
  --mypy-same-process   Run in the same process. Useful for debugging,
                        will create problems with import cache
  --mypy-extension-hook=MYPY_EXTENSION_HOOK
                        Fully qualified path to the extension hook function,
                        in case you need custom yaml keys. Has to be top-level
  --mypy-only-local-stub
                        mypy will ignore errors from site-packages