pytest-mypy-plugins


Namepytest-mypy-plugins JSON
Version 3.1.2 PyPI version JSON
download
home_pagehttps://github.com/TypedDjango/pytest-mypy-plugins
Summarypytest plugin for writing tests for mypy plugins
upload_time2024-03-31 17:47:57
maintainerNikita Sobolev
docs_urlNone
authorMaksim Kurnikov
requires_python>=3.8
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <img src="http://mypy-lang.org/static/mypy_light.svg" alt="mypy logo" width="300px"/>

# pytest plugin for testing mypy types, stubs, and plugins

[![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)
[![Checked with mypy](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/)
[![Gitter](https://badges.gitter.im/mypy-django/Lobby.svg)](https://gitter.im/mypy-django/Lobby)
[![PyPI](https://img.shields.io/pypi/v/pytest-mypy-plugins?color=blue)](https://pypi.org/project/pytest-mypy-plugins/)
[![Conda Version](https://img.shields.io/conda/vn/conda-forge/pytest-mypy-plugins.svg?color=blue)](https://anaconda.org/conda-forge/pytest-mypy-plugins)

## Installation

This package is available on [PyPI](https://pypi.org/project/pytest-mypy-plugins/)

```bash
pip install pytest-mypy-plugins
```

and [conda-forge](https://anaconda.org/conda-forge/pytest-mypy-plugins)

```bash
conda install -c conda-forge pytest-mypy-plugins
```

## Usage

### Running

Plugin, after installation, is automatically picked up by `pytest` therefore it is sufficient to
just execute:

```bash
pytest
```

### Paths

The `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:

```yml
- case: mypy_path_from_env
  main: |
    from pair import Pair

    instance: Pair
    reveal_type(instance)  # N: Revealed type is 'pair.Pair'
  env:
    - MYPYPATH=../fixtures
```


### What is a test case?

In 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 `.py` file                                                                     |
| `files`         | `Optional[List[File]]=[]`\*                            | List of extra files to simulate imports if needed                                                                   |
| `disable_cache` | `Optional[bool]=False`                                 | Set to `true` disables `mypy` caching                                                                               |
| `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 |
| `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`](https://docs.pytest.org/en/stable/parametrize.html)     |
| `skip`          | `str`                                                  | Expression evaluated with following globals set: `sys`, `os`, `pytest` and `platform`                               |
| `expect_fail`   | `bool`                                                 | Mark test case as an expected failure, like [`@pytest.mark.xfail`](https://docs.pytest.org/en/stable/skipping.html) |
| `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:

```python
class File:
    path: str
    content: Optional[str] = None
Parameter = Mapping[str, Any]
```

Implementation notes:

- `main` must be non-empty string that evaluates to valid **Python** code,
- `content` of each of extra files must evaluate to valid **Python** code,
- `parametrized` entries 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 `skip` is passed directly into
  [`eval`](https://docs.python.org/3/library/functions.html#eval). It is advised to take a peek and
  learn about how `eval` works.

Repository also offers a [JSONSchema](pytest_mypy_plugins/schema.json), 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
# yaml-language-server: $schema=https://raw.githubusercontent.com/typeddjango/pytest-mypy-plugins/master/pytest_mypy_plugins/schema.json
```

### Example

#### 1. Inline type expectations

```yaml
# 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
```

#### 2. `@parametrized`

```yaml
- 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`

#### 3. Longer type expectations

```yaml
- case: with_out
  main: |
    reveal_type('abc')
  out: |
    main:1: note: Revealed type is 'builtins.str'
```

#### 4. Regular expressions in expectations

```yaml
- case: expected_message_regex_with_out
  regex: yes
  main: |
    a = 'abc'
    reveal_type(a)
  out: |
    main:2: note: .*str.*
```

#### 5. Regular expressions specific lines of output.

```yaml
- case: expected_single_message_regex
  main: |
    a = 'hello'
    reveal_type(a)  # NR: .*str.*
```

## Options

```
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
  --mypy-closed-schema
                        Use closed schema to validate YAML test cases,
                        which won't allow any extra keys
                        (does not work well with `--mypy-extension-hook`)

```

## Further reading

- [Testing mypy stubs, plugins, and types](https://sobolevn.me/2019/08/testing-mypy-types)

## License

[MIT](https://github.com/typeddjango/pytest-mypy-plugins/blob/master/LICENSE)

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/TypedDjango/pytest-mypy-plugins",
    "name": "pytest-mypy-plugins",
    "maintainer": "Nikita Sobolev",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "mail@sobolevn.me",
    "keywords": null,
    "author": "Maksim Kurnikov",
    "author_email": "maxim.kurnikov@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/95/36/5411148fa0ad3242e38364152016a9d56758c0e0808fcb1909562f85b328/pytest-mypy-plugins-3.1.2.tar.gz",
    "platform": null,
    "description": "<img src=\"http://mypy-lang.org/static/mypy_light.svg\" alt=\"mypy logo\" width=\"300px\"/>\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### 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",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "pytest plugin for writing tests for mypy plugins",
    "version": "3.1.2",
    "project_urls": {
        "Homepage": "https://github.com/TypedDjango/pytest-mypy-plugins"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6cc2a75ad669251e71204c4bc06386d1d3cf1ff0593f85138ab4ccf28db792da",
                "md5": "7a8a5ab349fe53d6776adeef3445675d",
                "sha256": "3478ccb68e26a159e1287c4614c60f84cd0720e3895f174365c7440498234b9f"
            },
            "downloads": -1,
            "filename": "pytest_mypy_plugins-3.1.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "7a8a5ab349fe53d6776adeef3445675d",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 19976,
            "upload_time": "2024-03-31T17:47:55",
            "upload_time_iso_8601": "2024-03-31T17:47:55.713436Z",
            "url": "https://files.pythonhosted.org/packages/6c/c2/a75ad669251e71204c4bc06386d1d3cf1ff0593f85138ab4ccf28db792da/pytest_mypy_plugins-3.1.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "95365411148fa0ad3242e38364152016a9d56758c0e0808fcb1909562f85b328",
                "md5": "c4f435169e3d4f7589dadeecd816d0a7",
                "sha256": "14fa9b00e59713a6fdb88fcf04e8139b9467e117b98d61fc12038c60afb7febe"
            },
            "downloads": -1,
            "filename": "pytest-mypy-plugins-3.1.2.tar.gz",
            "has_sig": false,
            "md5_digest": "c4f435169e3d4f7589dadeecd816d0a7",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 26202,
            "upload_time": "2024-03-31T17:47:57",
            "upload_time_iso_8601": "2024-03-31T17:47:57.294399Z",
            "url": "https://files.pythonhosted.org/packages/95/36/5411148fa0ad3242e38364152016a9d56758c0e0808fcb1909562f85b328/pytest-mypy-plugins-3.1.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-31 17:47:57",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "TypedDjango",
    "github_project": "pytest-mypy-plugins",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "tox": true,
    "lcname": "pytest-mypy-plugins"
}
        
Elapsed time: 0.46892s