{"id":13800593,"url":"https://github.com/typeddjango/pytest-mypy-plugins","last_synced_at":"2025-05-15T09:06:18.674Z","repository":{"id":34162583,"uuid":"159567593","full_name":"typeddjango/pytest-mypy-plugins","owner":"typeddjango","description":"pytest plugin for testing mypy types, stubs, and plugins","archived":false,"fork":false,"pushed_at":"2025-02-14T05:12:52.000Z","size":201,"stargazers_count":113,"open_issues_count":28,"forks_count":27,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-05-08T09:40:41.127Z","etag":null,"topics":["mypy","mypy-plugins","mypy-stubs","pep484","pytest","pytest-plugin","python"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/pytest-mypy-plugins/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/typeddjango.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"typeddjango","open_collective":"typeddjangoorg"}},"created_at":"2018-11-28T21:29:10.000Z","updated_at":"2025-05-08T07:53:11.000Z","dependencies_parsed_at":"2023-11-09T12:29:21.336Z","dependency_job_id":"3d788364-d452-4032-ae56-c0a0d896e73a","html_url":"https://github.com/typeddjango/pytest-mypy-plugins","commit_stats":{"total_commits":145,"total_committers":27,"mean_commits":5.37037037037037,"dds":0.6965517241379311,"last_synced_commit":"3e2313c2473191165fab66294f13c77c2b64ee75"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typeddjango%2Fpytest-mypy-plugins","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typeddjango%2Fpytest-mypy-plugins/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typeddjango%2Fpytest-mypy-plugins/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typeddjango%2Fpytest-mypy-plugins/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/typeddjango","download_url":"https://codeload.github.com/typeddjango/pytest-mypy-plugins/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254093422,"owners_count":22013386,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mypy","mypy-plugins","mypy-stubs","pep484","pytest","pytest-plugin","python"],"created_at":"2024-08-04T00:01:14.086Z","updated_at":"2025-05-15T09:06:18.646Z","avatar_url":"https://github.com/typeddjango.png","language":"Python","readme":"\u003cimg src=\"http://mypy-lang.org/static/mypy_light.svg\" alt=\"mypy logo\" width=\"300px\"/\u003e\n\n# pytest plugin for testing mypy types, stubs, and plugins\n\n[![Tests Status](https://github.com/typeddjango/pytest-mypy-plugins/actions/workflows/test.yml/badge.svg)](https://github.com/typeddjango/pytest-mypy-plugins/actions/workflows/test.yml)\n[![Checked with mypy](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/)\n[![Gitter](https://badges.gitter.im/mypy-django/Lobby.svg)](https://gitter.im/mypy-django/Lobby)\n[![PyPI](https://img.shields.io/pypi/v/pytest-mypy-plugins?color=blue)](https://pypi.org/project/pytest-mypy-plugins/)\n[![Conda Version](https://img.shields.io/conda/vn/conda-forge/pytest-mypy-plugins.svg?color=blue)](https://anaconda.org/conda-forge/pytest-mypy-plugins)\n\n## Installation\n\nThis package is available on [PyPI](https://pypi.org/project/pytest-mypy-plugins/)\n\n```bash\npip install pytest-mypy-plugins\n```\n\nand [conda-forge](https://anaconda.org/conda-forge/pytest-mypy-plugins)\n\n```bash\nconda install -c conda-forge pytest-mypy-plugins\n```\n\n## Usage\n\n### Running\n\nPlugin, after installation, is automatically picked up by `pytest` therefore it is sufficient to\njust execute:\n\n```bash\npytest\n```\n\n### Asserting types\n\nThere are two ways to assert types.\nThe custom one and regular [`typing.assert_type`](https://docs.python.org/3/library/typing.html#typing.assert_type).\n\nOur custom type assertion uses `reveal_type` helper and custom output matchers:\n\n```yml\n- case: using_reveal_type\n  main: |\n    instance = 1\n    reveal_type(instance)  # N: Revealed type is 'builtins.int'\n```\n\nThis method also allows to use `# E:` for matching exact error messages and codes.\n\nBut, you can also use regular `assert_type`, examples can be [found here](https://github.com/typeddjango/pytest-mypy-plugins/blob/master/pytest_mypy_plugins/tests/test-assert-type.yml).\n\n### Paths\n\nThe `PYTHONPATH` and `MYPYPATH` environment variables, if set, are passed to `mypy` on invocation.\nThis may be helpful if you are testing a local plugin and need to provide an import path to it.\n\nBe aware that when `mypy` is run in a subprocess (the default) the test cases are run in temporary working directories\nwhere relative paths such as `PYTHONPATH=./my_plugin` do not reference the directory which you are running `pytest` from.\nIf you encounter this, consider invoking `pytest` with `--mypy-same-process` or make your paths absolute,\ne.g. `PYTHONPATH=$(pwd)/my_plugin pytest`.\n\nYou can also specify `PYTHONPATH`, `MYPYPATH`, or any other environment variable in `env:` section of `yml` spec:\n\n```yml\n- case: mypy_path_from_env\n  main: |\n    from pair import Pair\n\n    instance: Pair\n    reveal_type(instance)  # N: Revealed type is 'pair.Pair'\n  env:\n    - MYPYPATH=../fixtures\n```\n\n\n### What is a test case?\n\nIn general each test case is just an element in an array written in a properly formatted `YAML` file.\nOn top of that, each case must comply to following types:\n\n| Property        | Type                                                   | Description                                                                                                         |\n| --------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- |\n| `case`          | `str`                                                  | Name of the test case, complies to `[a-zA-Z0-9]` pattern                                                            |\n| `main`          | `str`                                                  | Portion of the code as if written in `.py` file                                                                     |\n| `files`         | `Optional[List[File]]=[]`\\*                            | List of extra files to simulate imports if needed                                                                   |\n| `disable_cache` | `Optional[bool]=False`                                 | Set to `true` disables `mypy` caching                                                                               |\n| `mypy_config`   | `Optional[str]`                                        | Inline `mypy` configuration, passed directly to `mypy` as `--config-file` option, possibly joined with `--mypy-pyproject-toml-file` or `--mypy-ini-file` contents if they are passed. By default is treated as `ini`, treated as `toml` only if `--mypy-pyproject-toml-file` is passed |\n| `env`           | `Optional[Dict[str, str]]={}`                          | Environmental variables to be provided inside of test run                                                           |\n| `parametrized`  | `Optional[List[Parameter]]=[]`\\*                       | List of parameters, similar to [`@pytest.mark.parametrize`](https://docs.pytest.org/en/stable/parametrize.html)     |\n| `skip`          | `str`                                                  | Expression evaluated with following globals set: `sys`, `os`, `pytest` and `platform`                               |\n| `expect_fail`   | `bool`                                                 | Mark test case as an expected failure, like [`@pytest.mark.xfail`](https://docs.pytest.org/en/stable/skipping.html) |\n| `regex`         | `str`                                                  | Allow regular expressions in comments to be matched against actual output. Defaults to \"no\", i.e. matches full text.|\n\n(*) Appendix to **pseudo** types used above:\n\n```python\nclass File:\n    path: str\n    content: Optional[str] = None\nParameter = Mapping[str, Any]\n```\n\nImplementation notes:\n\n- `main` must be non-empty string that evaluates to valid **Python** code,\n- `content` of each of extra files must evaluate to valid **Python** code,\n- `parametrized` entries must all be the objects of the same _type_. It simply means that each\n  entry must have **exact** same set of keys,\n- `skip` - an expression set in `skip` is passed directly into\n  [`eval`](https://docs.python.org/3/library/functions.html#eval). It is advised to take a peek and\n  learn about how `eval` works.\n\nRepository also offers a [JSONSchema](pytest_mypy_plugins/schema.json), with which\nit validates the input. It can also offer your editor auto-completions, descriptions, and validation.\n\nAll you have to do, add the following line at the top of your YAML file:\n```yaml\n# yaml-language-server: $schema=https://raw.githubusercontent.com/typeddjango/pytest-mypy-plugins/master/pytest_mypy_plugins/schema.json\n```\n\n### Example\n\n#### 1. Inline type expectations\n\n```yaml\n# typesafety/test_request.yml\n- case: request_object_has_user_of_type_auth_user_model\n  main: |\n    from django.http.request import HttpRequest\n    reveal_type(HttpRequest().user)  # N: Revealed type is 'myapp.models.MyUser'\n    # check that other fields work ok\n    reveal_type(HttpRequest().method)  # N: Revealed type is 'Union[builtins.str, None]'\n  files:\n    - path: myapp/__init__.py\n    - path: myapp/models.py\n      content: |\n        from django.db import models\n        class MyUser(models.Model):\n            pass\n```\n\n#### 2. `@parametrized`\n\n```yaml\n- case: with_params\n  parametrized:\n    - val: 1\n      rt: builtins.int\n    - val: 1.0\n      rt: builtins.float\n  main: |\n    reveal_type({{ val }})  # N: Revealed type is '{{ rt }}'\n```\n\nProperties that you can parametrize:\n- `main`\n- `mypy_config`\n- `out`\n\n#### 3. Longer type expectations\n\n```yaml\n- case: with_out\n  main: |\n    reveal_type('abc')\n  out: |\n    main:1: note: Revealed type is 'builtins.str'\n```\n\n#### 4. Regular expressions in expectations\n\n```yaml\n- case: expected_message_regex_with_out\n  regex: yes\n  main: |\n    a = 'abc'\n    reveal_type(a)\n  out: |\n    main:2: note: .*str.*\n```\n\n#### 5. Regular expressions specific lines of output.\n\n```yaml\n- case: expected_single_message_regex\n  main: |\n    a = 'hello'\n    reveal_type(a)  # NR: .*str.*\n```\n\n## Options\n\n```\nmypy-tests:\n  --mypy-testing-base=MYPY_TESTING_BASE\n                        Base directory for tests to use\n  --mypy-pyproject-toml-file=MYPY_PYPROJECT_TOML_FILE\n                        Which `pyproject.toml` file to use\n                        as a default config for tests.\n                        Incompatible with `--mypy-ini-file`\n  --mypy-ini-file=MYPY_INI_FILE\n                        Which `.ini` file to use as a default config for tests.\n                        Incompatible with `--mypy-pyproject-toml-file`\n  --mypy-same-process\n                        Run in the same process. Useful for debugging,\n                        will create problems with import cache\n  --mypy-extension-hook=MYPY_EXTENSION_HOOK\n                        Fully qualified path to the extension hook function,\n                        in case you need custom yaml keys. Has to be top-level\n  --mypy-only-local-stub\n                        mypy will ignore errors from site-packages\n  --mypy-closed-schema\n                        Use closed schema to validate YAML test cases,\n                        which won't allow any extra keys\n                        (does not work well with `--mypy-extension-hook`)\n\n```\n\n## Further reading\n\n- [Testing mypy stubs, plugins, and types](https://sobolevn.me/2019/08/testing-mypy-types)\n\n## License\n\n[MIT](https://github.com/typeddjango/pytest-mypy-plugins/blob/master/LICENSE)\n","funding_links":["https://github.com/sponsors/typeddjango","https://opencollective.com/typeddjangoorg"],"categories":["Tools"],"sub_categories":["Testing"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypeddjango%2Fpytest-mypy-plugins","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftypeddjango%2Fpytest-mypy-plugins","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypeddjango%2Fpytest-mypy-plugins/lists"}