Mypy static type checker plugin for Pytest

Related tags

Testing pytest-mypy
Overview

pytest-mypy

Mypy static type checker plugin for pytest

See Latest Release on PyPI

Features

  • Runs the mypy static type checker on your source files as part of your pytest test runs.
  • Does for mypy what the pytest-flake8 plugin does for flake8.
  • This is a work in progress – pull requests appreciated.

Installation

You can install "pytest-mypy" via pip from PyPI:

$ pip install pytest-mypy

Usage

You can enable pytest-mypy with the --mypy flag:

$ py.test --mypy test_*.py

Mypy supports reading configuration settings from a mypy.ini file. Alternatively, the plugin can be configured in a conftest.py to invoke mypy with extra options:

def pytest_configure(config):
    plugin = config.pluginmanager.getplugin('mypy')
    plugin.mypy_argv.append('--check-untyped-defs')

You can restrict your test run to only perform mypy checks and not any other tests by using the -m option:

py.test --mypy -m mypy test_*.py

License

Distributed under the terms of the MIT license, "pytest-mypy" is free and open source software

Issues

If you encounter any problems, please file an issue along with a detailed description.

Meta

Daniel Bader – @dbader_orghttps://dbader.org[email protected]

https://github.com/dbader/pytest-mypy

Comments
  • Add support for 3.8

    Add support for 3.8

    Just a nice quick change hopefully. I've ran tox and the tests passed but really I'm just making sure when used with 3.8 it no longer pulls in the version of mypy which depends on typed_ast as that's been removed in 3.8.

    I'm not very familiar with tox so correct me if I've made an erroneous change to the tox.ini (I ran tox -e py38 inside a 3.8-dev interpreter)

    opened by naphta 10
  • 0.8.1: pytest is failing because cannot find module named `is_always_missing`

    0.8.1: pytest is failing because cannot find module named `is_always_missing`

    I'm trying to package your module as an rpm package. So I'm using the typical PEP517 based build, install and test cycle used on building packages from non-root account.

    • python3 -sBm build -w --no-isolation
    • install .whl file in </install/prefix>
    • run pytest with PYTHONPATH pointing to sitearch and sitelib inside </install/prefix>

    May I ask where I can find that is_always_missing module? I canmot find it on pypi :/ Here is pytest output:

    + PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-pytest-mypy-0.8.1-2.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-pytest-mypy-0.8.1-2.fc35.x86_64/usr/lib/python3.8/site-packages
    + /usr/bin/pytest -ra
    =========================================================================== test session starts ============================================================================
    platform linux -- Python 3.8.12, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: /home/tkloczko/rpmbuild/BUILD/pytest-mypy-0.8.1, configfile: tox.ini, testpaths: tests
    plugins: mypy-0.8.1, forked-1.4.0, xdist-2.5.0, cov-3.0.0, cases-3.6.7, flake8-1.0.7
    collected 50 items
    
    tests/test_pytest_mypy.py ............FFF...................................                                                                                         [100%]
    
    ================================================================================= FAILURES =================================================================================
    _________________________________________________________________ test_mypy_ignore_missings_imports[True] __________________________________________________________________
    
    testdir = <Testdir local('/tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports0')>, xdist_args = ['-n', 'auto']
    
        def test_mypy_ignore_missings_imports(testdir, xdist_args):
            """
            Verify that --mypy-ignore-missing-imports
            causes mypy to ignore missing imports.
            """
            module_name = "is_always_missing"
            testdir.makepyfile(
                """
                    try:
                        import {module_name}
                    except ImportError:
                        pass
                """.format(
                    module_name=module_name,
                ),
            )
            result = testdir.runpytest_subprocess("--mypy", *xdist_args)
            mypy_file_checks = 1
            mypy_status_check = 1
            mypy_checks = mypy_file_checks + mypy_status_check
            result.assert_outcomes(failed=mypy_checks)
    >       result.stdout.fnmatch_lines(
                [
                    "2: error: Cannot find *module named '{module_name}'".format(
                        module_name=module_name,
                    ),
                ],
            )
    E       Failed: nomatch: "2: error: Cannot find *module named 'is_always_missing'"
    E           and: '============================= test session starts =============================='
    E           and: 'platform linux -- Python 3.8.12, pytest-6.2.5, py-1.11.0, pluggy-1.0.0'
    E           and: 'rootdir: /tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports0'
    E           and: 'plugins: mypy-0.8.1, forked-1.4.0, xdist-2.5.0, cov-3.0.0, cases-3.6.7, flake8-1.0.7'
    E           and: 'gw0 I / gw1 I / gw2 I / gw3 I / gw4 I / gw5 I / gw6 I / gw7 I / gw8 I / gw9 I / gw10 I / gw11 I'
    E           and: 'gw0 [2] / gw1 [2] / gw2 [2] / gw3 [2] / gw4 [2] / gw5 [2] / gw6 [2] / gw7 [2] / gw8 [2] / gw9 [2] / gw10 [2] / gw11 [2]'
    E           and: ''
    E           and: 'FF                                                                       [100%]'
    E           and: '=================================== FAILURES ==================================='
    E           and: '_________________________________ test session _________________________________'
    E           and: '[gw1] linux -- Python 3.8.12 /usr/bin/python3'
    E           and: 'mypy exited with status 1.'
    E           and: '_____________________ test_mypy_ignore_missings_imports.py _____________________'
    E           and: '[gw0] linux -- Python 3.8.12 /usr/bin/python3'
    E           and: '2: error: Cannot find implementation or library stub for module named "is_always_missing"'
    E           and: '2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports'
    E           and: '===================================== mypy ====================================='
    E           and: 'Found 1 error in 1 file (checked 1 source file)'
    E           and: '=========================== short test summary info ============================'
    E           and: 'FAILED test_mypy_ignore_missings_imports.py::mypy-status'
    E           and: 'FAILED test_mypy_ignore_missings_imports.py::mypy'
    E           and: '============================== 2 failed in 13.08s =============================='
    E       remains unmatched: "2: error: Cannot find *module named 'is_always_missing'"
    
    /home/tkloczko/rpmbuild/BUILD/pytest-mypy-0.8.1/tests/test_pytest_mypy.py:119: Failed
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    running: /usr/bin/python3 -mpytest --basetemp=/tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports0/runpytest-0 --mypy -n auto
         in: /tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports0
    ============================= test session starts ==============================
    platform linux -- Python 3.8.12, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: /tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports0
    plugins: mypy-0.8.1, forked-1.4.0, xdist-2.5.0, cov-3.0.0, cases-3.6.7, flake8-1.0.7
    gw0 I / gw1 I / gw2 I / gw3 I / gw4 I / gw5 I / gw6 I / gw7 I / gw8 I / gw9 I / gw10 I / gw11 I
    gw0 [2] / gw1 [2] / gw2 [2] / gw3 [2] / gw4 [2] / gw5 [2] / gw6 [2] / gw7 [2] / gw8 [2] / gw9 [2] / gw10 [2] / gw11 [2]
    
    FF                                                                       [100%]
    =================================== FAILURES ===================================
    _________________________________ test session _________________________________
    [gw1] linux -- Python 3.8.12 /usr/bin/python3
    mypy exited with status 1.
    _____________________ test_mypy_ignore_missings_imports.py _____________________
    [gw0] linux -- Python 3.8.12 /usr/bin/python3
    2: error: Cannot find implementation or library stub for module named "is_always_missing"
    2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
    ===================================== mypy =====================================
    Found 1 error in 1 file (checked 1 source file)
    =========================== short test summary info ============================
    FAILED test_mypy_ignore_missings_imports.py::mypy-status
    FAILED test_mypy_ignore_missings_imports.py::mypy
    ============================== 2 failed in 13.08s ==============================
    _________________________________________________________________ test_mypy_ignore_missings_imports[False] _________________________________________________________________
    
    testdir = <Testdir local('/tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports1')>, xdist_args = []
    
        def test_mypy_ignore_missings_imports(testdir, xdist_args):
            """
            Verify that --mypy-ignore-missing-imports
            causes mypy to ignore missing imports.
            """
            module_name = "is_always_missing"
            testdir.makepyfile(
                """
                    try:
                        import {module_name}
                    except ImportError:
                        pass
                """.format(
                    module_name=module_name,
                ),
            )
            result = testdir.runpytest_subprocess("--mypy", *xdist_args)
            mypy_file_checks = 1
            mypy_status_check = 1
            mypy_checks = mypy_file_checks + mypy_status_check
            result.assert_outcomes(failed=mypy_checks)
    >       result.stdout.fnmatch_lines(
                [
                    "2: error: Cannot find *module named '{module_name}'".format(
                        module_name=module_name,
                    ),
                ],
            )
    E       Failed: nomatch: "2: error: Cannot find *module named 'is_always_missing'"
    E           and: '============================= test session starts =============================='
    E           and: 'platform linux -- Python 3.8.12, pytest-6.2.5, py-1.11.0, pluggy-1.0.0'
    E           and: 'rootdir: /tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports1'
    E           and: 'plugins: mypy-0.8.1, forked-1.4.0, xdist-2.5.0, cov-3.0.0, cases-3.6.7, flake8-1.0.7'
    E           and: 'collected 2 items'
    E           and: ''
    E           and: 'test_mypy_ignore_missings_imports.py FF                                  [100%]'
    E           and: ''
    E           and: '=================================== FAILURES ==================================='
    E           and: '_____________________ test_mypy_ignore_missings_imports.py _____________________'
    E           and: '2: error: Cannot find implementation or library stub for module named "is_always_missing"'
    E           and: '2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports'
    E           and: '_________________________________ test session _________________________________'
    E           and: 'mypy exited with status 1.'
    E           and: '===================================== mypy ====================================='
    E           and: 'Found 1 error in 1 file (checked 1 source file)'
    E           and: '=========================== short test summary info ============================'
    E           and: 'FAILED test_mypy_ignore_missings_imports.py::mypy'
    E           and: 'FAILED test_mypy_ignore_missings_imports.py::mypy-status'
    E           and: '============================== 2 failed in 11.33s =============================='
    E       remains unmatched: "2: error: Cannot find *module named 'is_always_missing'"
    
    /home/tkloczko/rpmbuild/BUILD/pytest-mypy-0.8.1/tests/test_pytest_mypy.py:119: Failed
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    running: /usr/bin/python3 -mpytest --basetemp=/tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports1/runpytest-0 --mypy
         in: /tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports1
    ============================= test session starts ==============================
    platform linux -- Python 3.8.12, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: /tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports1
    plugins: mypy-0.8.1, forked-1.4.0, xdist-2.5.0, cov-3.0.0, cases-3.6.7, flake8-1.0.7
    collected 2 items
    
    test_mypy_ignore_missings_imports.py FF                                  [100%]
    
    =================================== FAILURES ===================================
    _____________________ test_mypy_ignore_missings_imports.py _____________________
    2: error: Cannot find implementation or library stub for module named "is_always_missing"
    2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
    _________________________________ test session _________________________________
    mypy exited with status 1.
    ===================================== mypy =====================================
    Found 1 error in 1 file (checked 1 source file)
    =========================== short test summary info ============================
    FAILED test_mypy_ignore_missings_imports.py::mypy
    FAILED test_mypy_ignore_missings_imports.py::mypy-status
    ============================== 2 failed in 11.33s ==============================
    _________________________________________________________________ test_mypy_ignore_missings_imports[None] __________________________________________________________________
    
    testdir = <Testdir local('/tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports2')>, xdist_args = ['-p', 'no:xdist']
    
        def test_mypy_ignore_missings_imports(testdir, xdist_args):
            """
            Verify that --mypy-ignore-missing-imports
            causes mypy to ignore missing imports.
            """
            module_name = "is_always_missing"
            testdir.makepyfile(
                """
                    try:
                        import {module_name}
                    except ImportError:
                        pass
                """.format(
                    module_name=module_name,
                ),
            )
            result = testdir.runpytest_subprocess("--mypy", *xdist_args)
            mypy_file_checks = 1
            mypy_status_check = 1
            mypy_checks = mypy_file_checks + mypy_status_check
            result.assert_outcomes(failed=mypy_checks)
    >       result.stdout.fnmatch_lines(
                [
                    "2: error: Cannot find *module named '{module_name}'".format(
                        module_name=module_name,
                    ),
                ],
            )
    E       Failed: nomatch: "2: error: Cannot find *module named 'is_always_missing'"
    E           and: '============================= test session starts =============================='
    E           and: 'platform linux -- Python 3.8.12, pytest-6.2.5, py-1.11.0, pluggy-1.0.0'
    E           and: 'rootdir: /tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports2'
    E           and: 'plugins: mypy-0.8.1, forked-1.4.0, xdist-2.5.0, cov-3.0.0, cases-3.6.7, flake8-1.0.7'
    E           and: 'collected 2 items'
    E           and: ''
    E           and: 'test_mypy_ignore_missings_imports.py FF                                  [100%]'
    E           and: ''
    E           and: '=================================== FAILURES ==================================='
    E           and: '_____________________ test_mypy_ignore_missings_imports.py _____________________'
    E           and: '2: error: Cannot find implementation or library stub for module named "is_always_missing"'
    E           and: '2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports'
    E           and: '_________________________________ test session _________________________________'
    E           and: 'mypy exited with status 1.'
    E           and: '===================================== mypy ====================================='
    E           and: 'Found 1 error in 1 file (checked 1 source file)'
    E           and: '=========================== short test summary info ============================'
    E           and: 'FAILED test_mypy_ignore_missings_imports.py::mypy'
    E           and: 'FAILED test_mypy_ignore_missings_imports.py::mypy-status'
    E           and: '============================== 2 failed in 11.25s =============================='
    E       remains unmatched: "2: error: Cannot find *module named 'is_always_missing'"
    
    /home/tkloczko/rpmbuild/BUILD/pytest-mypy-0.8.1/tests/test_pytest_mypy.py:119: Failed
    --------------------------------------------------------------------------- Captured stdout call ---------------------------------------------------------------------------
    running: /usr/bin/python3 -mpytest --basetemp=/tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports2/runpytest-0 --mypy -p no:xdist
         in: /tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports2
    ============================= test session starts ==============================
    platform linux -- Python 3.8.12, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
    rootdir: /tmp/pytest-of-tkloczko/pytest-551/test_mypy_ignore_missings_imports2
    plugins: mypy-0.8.1, forked-1.4.0, xdist-2.5.0, cov-3.0.0, cases-3.6.7, flake8-1.0.7
    collected 2 items
    
    test_mypy_ignore_missings_imports.py FF                                  [100%]
    
    =================================== FAILURES ===================================
    _____________________ test_mypy_ignore_missings_imports.py _____________________
    2: error: Cannot find implementation or library stub for module named "is_always_missing"
    2: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports
    _________________________________ test session _________________________________
    mypy exited with status 1.
    ===================================== mypy =====================================
    Found 1 error in 1 file (checked 1 source file)
    =========================== short test summary info ============================
    FAILED test_mypy_ignore_missings_imports.py::mypy
    FAILED test_mypy_ignore_missings_imports.py::mypy-status
    ============================== 2 failed in 11.25s ==============================
    ========================================================================= short test summary info ==========================================================================
    FAILED tests/test_pytest_mypy.py::test_mypy_ignore_missings_imports[True] - Failed: nomatch: "2: error: Cannot find *module named 'is_always_missing'"
    FAILED tests/test_pytest_mypy.py::test_mypy_ignore_missings_imports[False] - Failed: nomatch: "2: error: Cannot find *module named 'is_always_missing'"
    FAILED tests/test_pytest_mypy.py::test_mypy_ignore_missings_imports[None] - Failed: nomatch: "2: error: Cannot find *module named 'is_always_missing'"
    ================================================================= 3 failed, 47 passed in 588.13s (0:09:48) =================================================================
    
    opened by kloczek 9
  • Build requirements are too strict

    Build requirements are too strict

    I'd like to package pytest-mypy for OpenIndiana, but it is very hard to do so because build requirements for pytest-mypy are these (from pyproject.toml):

    [build-system]
    requires = ['setuptools ~= 50.3.0', 'setuptools-scm[toml] ~= 5.0.0', 'wheel ~= 0.36.0']
    build-backend = 'setuptools.build_meta'
    

    The latest acceptable versions of required tools are about two years old now.

    Could you please update pytest-mypy to relax its build requirements?

    Thank you.

    opened by mtelka 8
  • The exclude option is being ignored

    The exclude option is being ignored

    I am using pytest-mypy 0.8.0 to check ts_salobj (see link below). It had a generated version.py file that makes mypy unhappy so I am trying to exclude that (on branch tickets/DM-31000, see link below). My configuration works if I run mypy from the command line:

    mypy python tests
    

    but if run mypy using pytest-mypy then version.py is processed and the test fails:

    pytest -v -m mypy
    

    My configuration includes verbosity=1 and the output shows that version\.py is marked as excluded in both cases, but somehow pytest is pulling it in anyway.

    I am not sure how pytest is running mypy. Even with verbosity 2 I can't tell pytest-mypy tells mypy which files to test. I suspect that pytest-mypy is explicitly ordering mypy to test each file and am hoping there is some way to tell it to exclude version.py.

    The packages is here https://github.com/lsst-ts/ts_salobj/tree/tickets/DM-31000 and that ticket branch is the one with my attempted changes (including committing the offending version.py file, which normally is not in git).

    I admit that I am specifying the mypy config in setup.cfg and the pytest-mypy docs say to use mypy.ini. However, pytest-mypy is clearly using the configuration, based on the verbosity and the resulting log. Also moving or copying the mypy configuration to a new mypy.ini file makes no difference. Here is an excerpt from the printed output from pytest -v -m mypy:

    LOG:  Mypy Version:           0.812
    LOG:  Config File:            setup.cfg
    LOG:  Configured Executable:  /opt/lsst/software/stack/conda/miniconda3-py38_4.9.2/envs/lsst-scipipe-0.6.0/bin/python
    LOG:  Current Executable:     /opt/lsst/software/stack/conda/miniconda3-py38_4.9.2/envs/lsst-scipipe-0.6.0/bin/python
    LOG:  Cache Dir:              .mypy_cache
    LOG:  Compiled:               True
    LOG:  Exclude:                version\.py
    LOG:  Found source:           BuildSource(path='/home/saluser/tsrepos/ts_salobj/setup.py', module='setup', has_text=False, base_dir='/home/saluser/tsrepos/ts_salobj')
    ...
    LOG:  Found source:           BuildSource(path='/home/saluser/tsrepos/ts_salobj/python/lsst/ts/salobj/validator.py', module='salobj.validator', has_text=False, base_dir='/home/saluser/tsrepos/ts_salobj/python/lsst/ts')
    LOG:  Found source:           BuildSource(path='/home/saluser/tsrepos/ts_salobj/python/lsst/ts/salobj/version.py', module='salobj.version', has_text=False, base_dir='/home/saluser/tsrepos/ts_salobj/python/lsst/ts')
    LOG:  Found source:           BuildSource(path='/home/saluser/tsrepos/ts_salobj/python/lsst/ts/salobj/topics/__init__.py', module='salobj.topics', has_text=False, base_dir='/home/saluser/tsrepos/ts_salobj/python/lsst/ts')
    

    and a log from the command line:

    LOG:  Mypy Version:           0.812
    LOG:  Config File:            setup.cfg
    LOG:  Configured Executable:  /opt/lsst/software/stack/conda/miniconda3-py38_4.9.2/envs/lsst-scipipe-0.6.0/bin/python
    LOG:  Current Executable:     /opt/lsst/software/stack/conda/miniconda3-py38_4.9.2/envs/lsst-scipipe-0.6.0/bin/python
    LOG:  Cache Dir:              .mypy_cache
    LOG:  Compiled:               True
    LOG:  Exclude:                version\.py
    LOG:  Found source:           BuildSource(path='python/lsst/ts/salobj/__init__.py', module='salobj', has_text=False, base_dir='/home/saluser/tsrepos/ts_salobj/python/lsst/ts')
    ...
    LOG:  Found source:           BuildSource(path='python/lsst/ts/salobj/validator.py', module='salobj.validator', has_text=False, base_dir='/home/saluser/tsrepos/ts_salobj/python/lsst/ts')
    LOG:  Found source:           BuildSource(path='tests/data/minimal_salobj_controller.py', module='minimal_salobj_controller', has_text=False, base_dir='/home/saluser/tsrepos/ts_salobj/tests/data')
    LOG:  Found source:           BuildSource(path='/home/saluser/tsrepos/ts_salobj/python/lsst/ts/salobj/topics/__init__.py', module='salobj.topics', has_text=False, base_dir='/home/saluser/tsrepos/ts_salobj/python/lsst/ts')
    

    notice that version.py is not listed as a "Found source" in the second case.

    opened by r-owen 8
  • Update dependency from mypy-lang to mypy

    Update dependency from mypy-lang to mypy

    When trying to use a development snapshot of mypy (through pip install git+https://github.com/python/mypy.git\#egg\=mypy), the current setup.py is ignoring the existing mypy installation because it doesn't match mypy-lang, making such use impossible.

    Apparently mypy's maintainers managed to get access to mypy in PyPI, and their setup.py now builds using this very name.

    This fix consists of dropping the dependency on mypy-lang and adding a new one on mypy requiring version 0.470 or newer, which is the earliest version available on PyPI for this newly named package.

    opened by lastmikoi 8
  • Fix automatic release deployment

    Fix automatic release deployment

    Resolve #104

    This will not work until the project has repository secrets for PYPI_USERNAME and PYPI_PASSWORD: https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository

    I don't have permission to do that, so @dbader will have to do it.

    opened by dmtucker 7
  • Why not just use `mypy`and

    Why not just use `mypy`and "pytest`? What are the advantages of the "pytest-mypy" package?

    Sorry for my noob question, but what is the purpose of the package? I can run in a terminal locally or at a cloud's CI/CD the following two commands:

    >  mypy src/ && mypy tests/
    >  pytest tests/ 
    

    So why waste time on a new package development instead of just running two simple commands?

    opened by AIGeneratedUsername 7
  • AttributeError: 'MypyStatusItem' object has no attribute '_obj'

    AttributeError: 'MypyStatusItem' object has no attribute '_obj'

    Hey,

    I'm using both pytest-mypy and allure-pytest together and when I generate the report, I'm getting weird errors I don't know how to solve.

    Can you help me please?

    Test Code

    import allure
    
    
    def test_mypy1():
    
        def foo(arg: str) -> int:
            return arg
    
    
    @allure.severity(allure.severity_level.MINOR)
    def test_mypy2():
    
        def boo() -> int:
            return 10
    
    
    def test_mypy3():
    
        def boo() -> int:
            return 'I should have been an int'
    

    Error: AttributeError: 'MypyStatusItem' object has no attribute '_obj'

    cls = <class '_pytest.runner.CallInfo'>
    func = <function call_runtest_hook.<locals>.<lambda> at 0x7f855c16a3b0>
    when = 'setup'
    reraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)
    
        @classmethod
        def from_call(
            cls,
            func: "Callable[[], TResult]",
            when: "Literal['collect', 'setup', 'call', 'teardown']",
            reraise: Optional[
                Union[Type[BaseException], Tuple[Type[BaseException], ...]]
            ] = None,
        ) -> "CallInfo[TResult]":
            excinfo = None
            start = timing.time()
            precise_start = timing.perf_counter()
            try:
    >           result: Optional[TResult] = func()
    
    .venv/lib/python3.7/site-packages/_pytest/runner.py:311: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    >       lambda: ihook(item=item, **kwds), when=when, reraise=reraise
        )
    
    .venv/lib/python3.7/site-packages/_pytest/runner.py:255: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = <_HookCaller 'pytest_runtest_setup'>, args = ()
    kwargs = {'item': <MypyStatusItem mypy>}, notincall = set()
    
        def __call__(self, *args, **kwargs):
            if args:
                raise TypeError("hook calling supports only keyword arguments")
            assert not self.is_historic()
            if self.spec and self.spec.argnames:
                notincall = (
                    set(self.spec.argnames) - set(["__multicall__"]) - set(kwargs.keys())
                )
                if notincall:
                    warnings.warn(
                        "Argument(s) {} which are declared in the hookspec "
                        "can not be found in this hook call".format(tuple(notincall)),
                        stacklevel=2,
                    )
    >       return self._hookexec(self, self.get_hookimpls(), kwargs)
    
    .venv/lib/python3.7/site-packages/pluggy/hooks.py:286: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = <_pytest.config.PytestPluginManager object at 0x7f8558758150>
    hook = <_HookCaller 'pytest_runtest_setup'>
    methods = [<HookImpl plugin_name='nose', plugin=<module '_pytest.nose' from '/Users/nusnus/dev/flask_tester/.venv/lib/python3.7/...855c013450>>, <HookImpl plugin_name='logging-plugin', plugin=<_pytest.logging.LoggingPlugin object at 0x7f855c034b90>>]
    kwargs = {'item': <MypyStatusItem mypy>}
    
        def _hookexec(self, hook, methods, kwargs):
            # called from all hookcaller instances.
            # enable_tracing will set its own wrapping function at self._inner_hookexec
    >       return self._inner_hookexec(hook, methods, kwargs)
    
    .venv/lib/python3.7/site-packages/pluggy/manager.py:93: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    hook = <_HookCaller 'pytest_runtest_setup'>
    methods = [<HookImpl plugin_name='nose', plugin=<module '_pytest.nose' from '/Users/nusnus/dev/flask_tester/.venv/lib/python3.7/...855c013450>>, <HookImpl plugin_name='logging-plugin', plugin=<_pytest.logging.LoggingPlugin object at 0x7f855c034b90>>]
    kwargs = {'item': <MypyStatusItem mypy>}
    
        self._inner_hookexec = lambda hook, methods, kwargs: hook.multicall(
            methods,
            kwargs,
    >       firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
        )
    
    .venv/lib/python3.7/site-packages/pluggy/manager.py:87: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    hook_impls = [<HookImpl plugin_name='nose', plugin=<module '_pytest.nose' from '/Users/nusnus/dev/flask_tester/.venv/lib/python3.7/...855c013450>>, <HookImpl plugin_name='logging-plugin', plugin=<_pytest.logging.LoggingPlugin object at 0x7f855c034b90>>]
    caller_kwargs = {'item': <MypyStatusItem mypy>}, firstresult = False
    
        def _multicall(hook_impls, caller_kwargs, firstresult=False):
            """Execute a call into multiple python functions/methods and return the
            result(s).
        
            ``caller_kwargs`` comes from _HookCaller.__call__().
            """
            __tracebackhide__ = True
            results = []
            excinfo = None
            try:  # run impl and wrapper setup functions in a loop
                teardowns = []
                try:
                    for hook_impl in reversed(hook_impls):
                        try:
                            args = [caller_kwargs[argname] for argname in hook_impl.argnames]
                        except KeyError:
                            for argname in hook_impl.argnames:
                                if argname not in caller_kwargs:
                                    raise HookCallError(
                                        "hook call must provide argument %r" % (argname,)
                                    )
        
                        if hook_impl.hookwrapper:
                            try:
                                gen = hook_impl.function(*args)
                                next(gen)  # first yield
                                teardowns.append(gen)
                            except StopIteration:
                                _raise_wrapfail(gen, "did not yield")
                        else:
                            res = hook_impl.function(*args)
                            if res is not None:
                                results.append(res)
                                if firstresult:  # halt further impl calls
                                    break
                except BaseException:
                    excinfo = sys.exc_info()
            finally:
                if firstresult:  # first result hooks return a single value
                    outcome = _Result(results[0] if results else None, excinfo)
                else:
                    outcome = _Result(results, excinfo)
        
                # run all wrapper post-yield blocks
                for gen in reversed(teardowns):
                    try:
    >                   gen.send(outcome)
    
    .venv/lib/python3.7/site-packages/pluggy/callers.py:203: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = <allure_pytest.listener.AllureListener object at 0x7f855c013450>
    item = <MypyStatusItem mypy>
    
        @pytest.hookimpl(hookwrapper=True)
        def pytest_runtest_setup(self, item):
            if not self._cache.get(item.nodeid):
                uuid = self._cache.push(item.nodeid)
                test_result = TestResult(name=item.name, uuid=uuid, start=now(), stop=now())
                self.allure_logger.schedule_test(uuid, test_result)
        
            yield
        
            uuid = self._cache.get(item.nodeid)
            test_result = self.allure_logger.get_test(uuid)
            for fixturedef in _test_fixtures(item):
                group_uuid = self._cache.get(fixturedef)
                if not group_uuid:
                    group_uuid = self._cache.push(fixturedef)
                    group = TestResultContainer(uuid=group_uuid)
                    self.allure_logger.start_group(group_uuid, group)
                self.allure_logger.update_group(group_uuid, children=uuid)
            params = item.callspec.params if hasattr(item, 'callspec') else {}
        
    >       test_result.name = allure_name(item, params)
    
    .venv/lib/python3.7/site-packages/allure_pytest/listener.py:88: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    item = <MypyStatusItem mypy>, parameters = {}
    
        def allure_name(item, parameters):
            name = escape_name(item.name)
    >       title = allure_title(item)
    
    .venv/lib/python3.7/site-packages/allure_pytest/utils.py:110: 
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    item = <MypyStatusItem mypy>
    
        def allure_title(item):
    >       return getattr(item._obj, '__allure_display_name__', None)
    E       AttributeError: 'MypyStatusItem' object has no attribute '_obj'
    
    .venv/lib/python3.7/site-packages/allure_pytest/utils.py:34: AttributeError
    
    opened by Nusnus 7
  • False positives using when using pytest-xdist -f (--looponfail)

    False positives using when using pytest-xdist -f (--looponfail)

    When doing TDD, after the first mypy error, the plugin start emitting errors on collection.

    It will continue normally until you hit an actual mypy fail, then in the follow round (after mypy error is fixed) this warning is emitted forever until pytest is killed and restarted.

    Steps to Reproduce (assumes python 3.8 and pipenv available):

    1. mkdir ~/tmp20200412
    2. cd ~/tmp20200412
    3. git clone [email protected]:y2kbugger/test_driven_development_by_example_tdd_follow_along.git
    4. cd ./test*
    5. git checkout b0a2f56
    6. replicate versions exactly from Pipfile.lock pipenv sync
    7. put venv on PATH pipenv shell
    8. run pytest pytest --mypy -f money.py test_money.py

    In another terminal:

    1. cd ~/tmp20200412/test*
    2. cause mypy error echo 'lol: str = 2' >> money.py
    3. undo mypy error git checkout b0a2f56 -- .
    ###################################### waiting for changes #######################################
    ### Watching:   /home/y2k/devel/test_driven_development_by_example_tdd_follow_along
    # MODIFIED /home/y2k/devel/test_driven_development_by_example_tdd_follow_along/money.py
    ============================= test session starts ==============================
    platform linux -- Python 3.8.2, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
    rootdir: /home/y2k/devel/test_driven_development_by_example_tdd_follow_along
    plugins: forked-1.1.3, mypy-0.6.1, xdist-1.31.0, flake8-1.0.4
    collected 0 items / 1 error
    collected 0 items / 1 error
    
    ==================================== ERRORS ====================================
    ________________________ ERROR collecting test session _________________________
    ../../.local/share/virtualenvs/test_driven_development_by_example_tdd_fol-TPMT2dI5/lib/python3.8/site-packages/_pytest/runner.py:244: in from_call
        result = func()
    ../../.local/share/virtualenvs/test_driven_development_by_example_tdd_fol-TPMT2dI5/lib/python3.8/site-packages/_pytest/runner.py:264: in <lambda>
        call = CallInfo.from_call(lambda: list(collector.collect()), "collect")
    ../../.local/share/virtualenvs/test_driven_development_by_example_tdd_fol-TPMT2dI5/lib/python3.8/site-packages/_pytest/main.py:498: in collect
        yield from self._collect(fspath, parts)
    ../../.local/share/virtualenvs/test_driven_development_by_example_tdd_fol-TPMT2dI5/lib/python3.8/site-packages/_pytest/main.py:537: in _collect
        assert not names, "invalid arg {!r}".format((argpath, names))
    E   AssertionError: invalid arg (local('/home/y2k/devel/test_driven_development_by_example_tdd_follow_along'), ['mypy'])
    =========================== short test summary info ============================
    ERROR  - AssertionError: invalid arg (local('/home/y2k/devel/test_driven_deve...
    !!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
    =============================== 1 error in 0.22s ===============================
    ######################################### LOOPONFAILING ##########################################
    money.py::mypy
    test_money.py::test_multiplication
    test_money.py::test_franc_multiplication
    test_money.py::test_equality
    test_money.py::test_currency
    ::mypy
    ###################################### waiting for changes #######################################
    ### Watching:   /home/y2k/devel/test_driven_development_by_example_tdd_follow_along
    

    Note I kill with keyboard interrupt here:

    ^C
    

    Then everything goes fine again:

    (test_driven_development_by_example_tdd_follow_along) [y2k@15r test_driven_development_by_example_tdd_follow_along]
    $ pytest --mypy -f money.py test_money.py 
    ============================= test session starts ==============================
    platform linux -- Python 3.8.2, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
    rootdir: /home/y2k/devel/test_driven_development_by_example_tdd_follow_along
    plugins: forked-1.1.3, mypy-0.6.1, xdist-1.31.0, flake8-1.0.4
    collected 7 items
    collected 7 items
    
    money.py .                                                               [ 12%]
    test_money.py ......                                                     [ 87%]
    . .                                                                      [100%]. [100%]
    ===================================== mypy =====================================
    
    Success: no issues found in 2 source files
    ============================== 9 passed in 0.34s ===============================
    ###################################### waiting for changes #######################################
    ### Watching:   /home/y2k/devel/test_driven_development_by_example_tdd_follow_along
    
    opened by y2kbugger 6
  • Only depend on mypy.api

    Only depend on mypy.api

    Fixes #6

    I think we should strongly discourage such use of interfaces internal to mypy. The only public APIs are the command line and the mypy.api module. https://github.com/python/mypy/issues/4681#issuecomment-371037599

    opened by dmtucker 6
  • Add --mypy-config option

    Add --mypy-config option

    Hello! I have not found how to pass path to mypy config?

    I want something like: pytest --mypy --mypy-config tox.ini

    It's because mypy isn't read config from tox.

    opened by pbelskiy 4
  • Upgrading to 0.10.2 leads to `exceptiongroup` error

    Upgrading to 0.10.2 leads to `exceptiongroup` error

    After upgrading to v0.10.2 my CI system started failing, giving the following error:

    Traceback (most recent call last):
      File "/home/alex/code/FINESSE/.venv/bin/pytest", line 5, in <module>
        from pytest import console_main
      File "/home/alex/code/FINESSE/.venv/lib/python3.9/site-packages/pytest/__init__.py", line 5, in <module>
        from _pytest._code import ExceptionInfo
      File "/home/alex/code/FINESSE/.venv/lib/python3.9/site-packages/_pytest/_code/__init__.py", line 2, in <module>
        from .code import Code
      File "/home/alex/code/FINESSE/.venv/lib/python3.9/site-packages/_pytest/_code/code.py", line 60, in <module>
        from exceptiongroup import BaseExceptionGroup
    ModuleNotFoundError: No module named 'exceptiongroup'
    

    Full output here: https://github.com/ImperialCollegeLondon/FINESSE/pull/58

    It appears that the exceptiongroup package is not being installed via poetry, though it isn't obvious why.

    Any ideas?

    opened by alexdewar 1
  • Add --no-mypy option to disable mypy check

    Add --no-mypy option to disable mypy check

    Right now I have --mypy in my pytest.ini file so that mypy runs by default when my tests are run, both locally and in CI

    However, when I'm quickly iterating in testing a new feature, I would like to skip the mypy check since I first just want to make sure that the feature works.

    Having a --no-mypy option to pass through to pytest when running locally would be great, rather than having to just deal with the mypy run each time, or go and manually modify my pytest.ini file to comment out the --mypy option.

    The pytest-pylint and pytest-cov plugins provide this functionality:

    • https://github.com/carsongee/pytest-pylint/blob/781d6a8d67377b543756d0123c6259b8df77c0a8/pytest_pylint/plugin.py#L33-L38
    • https://github.com/pytest-dev/pytest-cov/blob/00713b3fec90cb8c98a9e4bfb3212e574c08e67b/src/pytest_cov/plugin.py#L110-L112

    I'm happy to add a PR if you agree that this is a worthwhile feature

    opened by pwildenhain 1
  • mypy exited with status 1 - no error messages shown

    mypy exited with status 1 - no error messages shown

    I have some type errors in my code, and would like to find them by running mypy via pytest-mypy. When I run pytest, I get:

    =========================================================================== test session starts ============================================================================
    platform linux -- Python 3.6.9, pytest-6.2.3, py-1.10.0, pluggy-0.13.1 -- <venv>
    cachedir: .pytest_cache
    rootdir: <project-root>, configfile: setup.cfg, testpaths: proof_of_concept, tests
    plugins: cov-2.11.1, pycodestyle-2.2.0, pydocstyle-2.2.0, mypy-0.8.1
    collected 154 items                                                                                                                                                        
    
    proof_of_concept/__init__.py::mypy PASSED
    proof_of_concept/__init__.py::mypy-status FAILED
    
    ================================================================================= FAILURES =================================================================================
    _______________________________________________________________________________ test session _______________________________________________________________________________
    mypy exited with status 1.
    

    This suggests that there were some errors, but it doesn't show what they were, so I cannot fix them. Running mypy separately reveals a bunch of issues in proof_of_concept/rest/registry_client.py.

    Looking at the pytest-mypy source, it seems that this can happen if mypy checks a file that has not been collected. I'm importing the problem file from the file under test, and mypy gives a bunch of errors about this imported file. I guess the ::mypy test passes anyway, because the errors are not in the file under test. However, pytest-mypy then generates an error using this second mypy-status result, because mypy returned a non-zero exit code.

    Ignoring the errors makes sense I think, they should show up later when the problem file itself is tested. Unfortunately, we never get to that point, because I'm running with -x, which stops the tests as soon as the first error is found, and no error messages are shown for the mypy-status failure, so I cannot fix them.

    I'm a bit confused about the current intent of the pytest-mypy code. There's a comment suggesting that the ::mypy test is intended to fail even if mypy only shows errors in files that weren't collected, and that that is why there's the ::mypy-status result. On the other hand, there used to be a test that checked that no MypyStatusItem was created unless there was at least one MypyFileItem, which I think means the opposite. That was removed in https://github.com/dbader/pytest-mypy/commit/cd459a48ce11d24e1bddf6877ef53f7d26cf3daf however, which also introduced this -status result.

    In my opinion, a mypy failure only because of errors in imported files should either be considered an error in the file under test, in which case the error should be printed, or it should not be considered an error in the file under test, in which case all tests related to that file should pass and the non-zero exit code ignored. The latter makes more sense to me.

    opened by LourensVeen 3
  • Recommended way to set report path?

    Recommended way to set report path?

    Hi, thanks for this excellent plugin! :heart:

    We are running pytest like so; pytest tests/unit_tests and this generates a bunch of reports. Then we also run pytest tests/component_tests, which also generates a bunch of (different) reports. I use a setup.cfg file to configure both pytest and mypy.

    Now, ideally, we want the mypy reports to be named accordingly ("unit" vs "component" respectively). Do you have a recommended approach on how to achieve this? Right now, I've created a simple pytest plugin which analyses pytest's config.args and determines which type of test is executing and then it does the following:

    plugin = config.pluginmanager.getplugin("mypy")
    plugin.mypy_argv.append(f"--html-report=reports/mypy/{test_type}")
    

    But to me, this seems both hacky and a little excessive. There must be some easier way to achieve this? Any ideas? 😃

    opened by fredrikaverpil 1
  • Expected mypy errors

    Expected mypy errors

    I'm working on a module specifically for use with typing, so I have tests that I expect to raise mypy warnings. It doesn't look like there's a way to mark tests as having expected errors.

    opened by dcbaker 3
Releases(v0.10.3)
Owner
Dan Bader
Full-stack Pythonista & Python Coach. Write Clean and Pythonic code with my free tutorials, books, and courses.
Dan Bader
pytest plugin providing a function to check if pytest is running.

pytest-is-running pytest plugin providing a function to check if pytest is running. Installation Install with: python -m pip install pytest-is-running

Adam Johnson 21 Nov 1, 2022
A pytest plugin to run an ansible collection's unit tests with pytest.

pytest-ansible-units An experimental pytest plugin to run an ansible collection's unit tests with pytest. Description pytest-ansible-units is a pytest

Community managed Ansible repositories 9 Dec 9, 2022
ApiPy was created for api testing with Python pytest framework which has also requests, assertpy and pytest-html-reporter libraries.

ApiPy was created for api testing with Python pytest framework which has also requests, assertpy and pytest-html-reporter libraries. With this f

Mustafa 1 Jul 11, 2022
Playwright Python tool practice pytest pytest-bdd screen-play page-object allure cucumber-report

pytest-ui-automatic Playwright Python tool practice pytest pytest-bdd screen-play page-object allure cucumber-report How to run Run tests execute_test

moyu6027 11 Nov 8, 2022
Pytest-rich - Pytest + rich integration (proof of concept)

pytest-rich Leverage rich for richer test session output. This plugin is not pub

Bruno Oliveira 170 Dec 2, 2022
A Django plugin for pytest.

Welcome to pytest-django! pytest-django allows you to test your Django project/applications with the pytest testing tool. Quick start / tutorial Chang

pytest-dev 1.1k Dec 31, 2022
A command-line tool and Python library and Pytest plugin for automated testing of RESTful APIs, with a simple, concise and flexible YAML-based syntax

1.0 Release See here for details about breaking changes with the upcoming 1.0 release: https://github.com/taverntesting/tavern/issues/495 Easier API t

null 909 Dec 15, 2022
Coverage plugin for pytest.

Overview docs tests package This plugin produces coverage reports. Compared to just using coverage run this plugin does some extras: Subprocess suppor

pytest-dev 1.4k Dec 29, 2022
pytest plugin for distributed testing and loop-on-failures testing modes.

xdist: pytest distributed testing plugin The pytest-xdist plugin extends pytest with some unique test execution modes: test run parallelization: if yo

pytest-dev 1.1k Dec 30, 2022
Plugin for generating HTML reports for pytest results

pytest-html pytest-html is a plugin for pytest that generates a HTML report for test results. Resources Documentation Release Notes Issue Tracker Code

pytest-dev 548 Dec 28, 2022
:game_die: Pytest plugin to randomly order tests and control random.seed

pytest-randomly Pytest plugin to randomly order tests and control random.seed. Features All of these features are on by default but can be disabled wi

pytest-dev 471 Dec 30, 2022
A rewrite of Python's builtin doctest module (with pytest plugin integration) but without all the weirdness

The xdoctest package is a re-write of Python's builtin doctest module. It replaces the old regex-based parser with a new abstract-syntax-tree based pa

Jon Crall 174 Dec 16, 2022
pytest plugin for manipulating test data directories and files

pytest-datadir pytest plugin for manipulating test data directories and files. Usage pytest-datadir will look up for a directory with the name of your

Gabriel Reis 191 Dec 21, 2022
pytest plugin that let you automate actions and assertions with test metrics reporting executing plain YAML files

pytest-play pytest-play is a codeless, generic, pluggable and extensible automation tool, not necessarily test automation only, based on the fantastic

pytest-dev 67 Dec 1, 2022
pytest plugin for a better developer experience when working with the PyTorch test suite

pytest-pytorch What is it? pytest-pytorch is a lightweight pytest-plugin that enhances the developer experience when working with the PyTorch test sui

Quansight 39 Nov 18, 2022
Pytest plugin for testing the idempotency of a function.

pytest-idempotent Pytest plugin for testing the idempotency of a function. Usage pip install pytest-idempotent Documentation Suppose we had the follo

Tyler Yep 3 Dec 14, 2022
A pytest plugin, that enables you to test your code that relies on a running PostgreSQL Database

This is a pytest plugin, that enables you to test your code that relies on a running PostgreSQL Database. It allows you to specify fixtures for PostgreSQL process and client.

Clearcode 252 Dec 21, 2022
A pytest plugin that enables you to test your code that relies on a running Elasticsearch search engine

pytest-elasticsearch What is this? This is a pytest plugin that enables you to test your code that relies on a running Elasticsearch search engine. It

Clearcode 65 Nov 10, 2022
This is a pytest plugin, that enables you to test your code that relies on a running MongoDB database

This is a pytest plugin, that enables you to test your code that relies on a running MongoDB database. It allows you to specify fixtures for MongoDB process and client.

Clearcode 19 Oct 21, 2022