[
  {
    "path": ".bumpversion.cfg",
    "content": "[bumpversion]\ncurrent_version = 2.2.0\ncommit = True\ntag = True\n\n[bumpversion:file:pyproject.toml]\nsearch = version = \"{current_version}\"\nreplace = version = \"{new_version}\"\n\n[bumpversion:file:README.md]\nsearch = **Unreleased**\nreplace = **Unreleased**\n\t\n\t...\n\t\n\t**{new_version} - {now:%Y-%m-%d}**\n\n[bumpversion:file:flake8_pytest_style/plugin.py]\nsearch = __version__ = \"{current_version}\"\nreplace = __version__ = \"{new_version}\"\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug.md",
    "content": "---\nname: Bug\nabout: Report a bug in the plugin\ntitle: When I have {{ SOMETHING EXPECTED }} in test, {{ AN UNEXPECTED THING }} happens\nlabels: bug\nassignees: ''\n\n---\n\n# Bug report\n\n## What's wrong\n\n<!--\nPlease describe what is not working. Perhaps the plugin reports a violation when it shouldn't, or vice versa?\nPlease attach a code sample which reproduces the problem.\n-->\n\n## How it should work\n\n<!-- Please describe the expected behaviour of the plugin in the given case. -->\n\n## System information\n\n* Operating system:\n* Python version:\n* flake8 version:\n* flake8-pytest-style version:\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/rule-request.md",
    "content": "---\nname: Rule request\nabout: Suggest a new rule for the plugin\ntitle: I want a rule that will {{ DO SOMETHING AWESOME }}\nlabels: enhancement, rule request\nassignees: ''\n\n---\n\n# Rule request\n\n## Description\n\n<!-- What do you think the plugin should check? Please provide examples of good and bad code. -->\n\n## Rationale\n\n<!-- Why do you think this is a good idea for a rule? -->\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n- package-ecosystem: pip\n  directory: \"/\"\n  schedule:\n    interval: daily\n    time: \"02:00\"\n  open-pull-requests-limit: 10\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\non:\n  push:\n    branches: [master]\n    tags: ['*']\n  pull_request:\n\njobs:\n  ci:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        python-version:\n          - \"3.10\"\n          - 3.11\n          - 3.12\n          - 3.13\n          - 3.14\n\n    steps:\n      - uses: actions/checkout@v5\n\n      - uses: actions/setup-python@v6\n        with:\n          python-version: ${{ matrix.python-version }}\n\n      - uses: snok/install-poetry@v1\n        with:\n          version: 2.2.1\n\n      - name: Show environment info\n        run: |\n          python --version\n          pip --version\n          poetry --version\n          poetry config --list\n\n      - name: Setup dependencies cache\n        uses: actions/cache@v4\n        with:\n          path: ~/.cache/pypoetry/virtualenvs\n          key: ${{ runner.os }}-${{ matrix.python-version }}-poetry-${{ hashFiles('poetry.lock') }}\n\n      - name: Install dependencies\n        run: |\n          poetry install\n          pip install codecov\n\n      - name: Run lint\n        run: make lint\n\n      - name: Run tests\n        run: make test\n\n      - name: Upload coverage data\n        run: codecov\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\non:\n  workflow_dispatch:\n\njobs:\n  release:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        python-version:\n          - 3.14\n\n    steps:\n      - uses: actions/checkout@v5\n\n      - uses: actions/setup-python@v6\n        with:\n          python-version: ${{ matrix.python-version }}\n\n      - uses: snok/install-poetry@v1\n        with:\n          version: 2.2.1\n\n      - name: Setup dependencies cache\n        uses: actions/cache@v4\n        with:\n          path: ~/.cache/pypoetry/virtualenvs\n          key: ${{ runner.os }}-${{ matrix.python-version }}-poetry-${{ hashFiles('poetry.lock') }}\n\n      - name: Install dependencies\n        run: poetry install\n\n      - name: Build distribution\n        run: |\n          poetry run ./scripts/pypi_readme.py\n          poetry build\n\n      - name: Publish to PyPI\n        run: poetry publish --no-interaction\n        env:\n          POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\npip-wheel-metadata/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\nREADME-pypi.md\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n.pytest_cache/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n\n# IDE\n.idea/\n.vscode/\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Mikhail Burshteyn\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": ".PHONY: init test test-cov lint format\n\nCODE = flake8_pytest_style\nTEST = poetry run pytest --verbosity=2 --showlocals --strict-markers --cov=$(CODE)\n\ninit:\n\tpoetry install\n\techo '#!/bin/sh\\nmake lint test\\n' > .git/hooks/pre-commit\n\tchmod +x .git/hooks/pre-commit\n\ntest:\n\t$(TEST) -k \"$(k)\"\n\ntest-cov:\n\t$(TEST) --cov-report=html\n\nlint:\n\tpoetry run flake8 --jobs 4 --statistics --show-source $(CODE) tests scripts\n\tpoetry run pylint --jobs 4 --rcfile=setup.cfg $(CODE)\n\tpoetry run mypy $(CODE) tests scripts\n\tpoetry run black --check $(CODE) tests scripts\n\tpoetry run pytest --dead-fixtures --dup-fixtures\n\nformat:\n\tpoetry run isort $(CODE) tests scripts\n\tpoetry run black $(CODE) tests scripts\n\nbump_major:\n\tpoetry run bumpversion major\n\nbump_minor:\n\tpoetry run bumpversion minor\n\nbump_patch:\n\tpoetry run bumpversion patch\n"
  },
  {
    "path": "README.md",
    "content": "# flake8-pytest-style\n\n[![pypi](https://badge.fury.io/py/flake8-pytest-style.svg)](https://pypi.org/project/flake8-pytest-style)\n[![Python: 3.10+](https://img.shields.io/badge/Python-3.10+-blue.svg)](https://pypi.org/project/flake8-pytest-style)\n[![Downloads](https://img.shields.io/pypi/dm/flake8-pytest-style.svg)](https://pypistats.org/packages/flake8-pytest-style)\n[![Build Status](https://github.com/m-burst/flake8-pytest-style/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/m-burst/flake8-pytest-style/actions/workflows/ci.yml)\n[![Code coverage](https://codecov.io/gh/m-burst/flake8-pytest-style/branch/master/graph/badge.svg)](https://codecov.io/gh/m-burst/flake8-pytest-style)\n[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://en.wikipedia.org/wiki/MIT_License)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)\n\n## Description\n\nA `flake8` plugin checking common style issues or inconsistencies with `pytest`-based tests.\n\nCurrently the following errors are reported:\n\n| Code    | Description |\n| ------- | ----------- |\n| [PT001] | use @pytest.fixture over @pytest.fixture() <br> (configurable by `pytest-fixture-no-parentheses`) |\n| [PT002] | configuration for fixture '{name}' specified via positional args, use kwargs |\n| [PT003] | scope='function' is implied in @pytest.fixture() |\n| [PT004] | fixture '{name}' does not return anything, add leading underscore |\n| [PT005] | fixture '{name}' returns a value, remove leading underscore |\n| [PT006] | wrong name(s) type in @pytest.mark.parametrize, expected {expected_type} <br> (configurable by `pytest-parametrize-names-type`) |\n| [PT007] | wrong values type in @pytest.mark.parametrize, expected {expected_type} <br> (configurable by `pytest-parametrize-values-type` and `pytest-parametrize-values-row-type`) |\n| [PT008] | use return_value= instead of patching with lambda |\n| [PT009] | use a regular assert instead of unittest-style '{assertion}' |\n| [PT010] | set the expected exception in pytest.raises() |\n| [PT011] | pytest.raises({exception}) is too broad, set the match parameter or use a more specific exception <br> (configurable by `pytest-raises-require-match-for`) |\n| [PT012] | pytest.raises() block should contain a single simple statement |\n| [PT013] | found incorrect import of pytest, use simple 'import pytest' instead |\n| [PT014] | found duplicate test cases {indexes} in @pytest.mark.parametrize |\n| [PT015] | assertion always fails, replace with pytest.fail() |\n| [PT016] | no message passed to pytest.fail() |\n| [PT017] | found assertion on exception {name} in except block, use pytest.raises() instead |\n| [PT018] | assertion should be broken down into multiple parts |\n| [PT019] | fixture {name} without value is injected as parameter, use @pytest.mark.usefixtures instead |\n| [PT020] | @pytest.yield_fixture is deprecated, use @pytest.fixture |\n| [PT021] | use yield instead of request.addfinalizer |\n| [PT022] | no teardown in fixture {name}, use return instead of yield |\n| [PT023] | use @pytest.mark.foo over @pytest.mark.foo() <br> (configurable by `pytest-mark-no-parentheses`) |\n| [PT024] | pytest.mark.asyncio is unnecessary for fixtures |\n| [PT025] | pytest.mark.usefixtures has no effect on fixtures |\n| [PT026] | useless pytest.mark.usefixtures without parameters | \n| [PT027] | use pytest.raises() instead of unittest-style '{assertion}' |\n| [PT028] | test function {name} has default value for argument {arg}, remove it |\n| [PT029] | set the expected warning in pytest.warns() |\n| [PT030] | pytest.warns({warning}) is too broad, set the match parameter or use a more specific warning <br> (configurable by `pytest-warns-require-match-for`) |\n| [PT031] | pytest.warns() block should contain a single simple statement |\n\n## Installation\n\n    pip install flake8-pytest-style\n\n## Configuration\n\nThe plugin has the following configuration options:\n\n* `pytest-fixture-no-parentheses` &mdash; see [PT001]\n* `pytest-parametrize-names-type` &mdash; see [PT006]\n* `pytest-parametrize-values-type` &mdash; see [PT007]\n* `pytest-parametrize-values-row-type` &mdash; see [PT007]\n* `pytest-raises-require-match-for` &mdash; see [PT011]\n* `pytest-mark-no-parentheses` &mdash; see [PT023]\n* `pytest-warns-require-match-for` &mdash; see [PT030]\n\n## For developers\n\n### Install deps and setup pre-commit hook\n\n    make init\n\n### Run linters, autoformat, tests etc.\n\n    make format lint test\n\n### Bump new version\n\n    make bump_major\n    make bump_minor\n    make bump_patch\n\n## License\n\nMIT\n\n## Change Log\n\n**Unreleased**\n\n...\n\n**2.2.0 - 2025-10-20**\n\n* require at least Python 3.10\n* support Python 3.14\n\n**2.1.0 - 2025-01-10**\n\n* support `reason=` kwarg in `pytest.fail` for [PT016]\n* add [PT028] (checks for default values in test functions)\n* add [PT029] (checks for `pytest.warns` without expected warning)\n* add [PT030] (checks for too broad `pytest.warns` clauses)\n* add [PT031] (checks for multiple statements in `pytest.warns` blocks)\n* require at least Python 3.9\n* support Python 3.13\n\n**2.0.0 - 2024-04-01**\n\n* **BREAKING:** invert default values for `pytest-fixture-no-parentheses` and `pytest-mark-no-parentheses`\n  to conform with `pytest` official style\n  * If you get a lot of [PT001] or [PT023] violations after upgrading, consider setting explicit values\n    for these configuration options\n* require at least Python 3.8.1\n* support Python 3.12\n\n**1.7.2 - 2023-02-15**\n\n* fix false positive for [PT009] on `pytest.fail`\n\n**1.7.1 - 2023-02-15**\n\n* update list of unittest-style assert methods for [PT009]/[PT027]\n\n**1.7.0 - 2023-02-09**\n\n* require at least Python 3.7.2\n* support Python 3.11\n* add [PT027] (checks for unittest-style `assertRaises`)\n\n**1.6.0 - 2021-12-23**\n\n* require at least Python 3.6.2\n* expose `py.typed` file\n\n**1.5.1 - 2021-11-05**\n\n* better wording for [PT011]\n* support Python 3.10\n\n**1.5.0 - 2021-06-18**\n\n* add [PT025] (checks for erroneous `pytest.mark.usefixtures` on fixtures)\n* add [PT026] (checks for `pytest.mark.usefixtures` without parameters)\n\n**1.4.4 - 2021-06-17**\n\n* fix [PT023] not checking marks in classes\n* fix [PT004] incorrectly firing on fixtures with `yield from`\n\n**1.4.2 - 2021-05-24**\n\n* update `flake8-plugin-utils` version to improve stability\n\n**1.4.1 - 2021-04-01**\n\n* fix argparse-related warnings\n\n**1.4.0 - 2021-03-14**\n\n* add [PT023] (checks for parentheses consistency in `pytest.mark` usage)\n* add [PT024] (checks for unnecessary `pytest.mark.asyncio` on fixtures)\n* fix [PT004], [PT005] firing on abstract fixtures\n* fix [PT012] firing on `with` statements containing a single `pass`\n\n**1.3.0 - 2020-08-30**\n\n* add [PT022] (checks for `yield` fixtures without teardown)\n\n**1.2.3 - 2020-08-06**\n\n* update `flake8-plugin-utils` dependency to fix encoding problems on Windows\n\n**1.2.2 - 2020-07-23**\n\n* fix [PT004]/[PT005] inspecting returns of nested functions\n\n**1.2.1 - 2020-06-15**\n\n* fix [PT021] for factory fixtures (#46)\n\n**1.2.0 - 2020-06-12**\n\n* support scoped `mocker` fixtures from `pytest-mock` for [PT008]\n* check for positional-only lambda arguments in [PT008]\n* add [PT020] (checks for `pytest.yield_fixture`)\n* add [PT021] (checks for `request.addfinalizer`)\n* add documentation pages for all rules\n\n**1.1.1 - 2020-04-17**\n\n* fix [PT011] not reporting `match=''` as a violation\n\n**1.1.0 - 2020-04-14**\n\n* add [PT015] (checks for `assert False`)\n* add [PT016] (checks for `pytest.fail()` without message)\n* add [PT017] (checks for assertions on exceptions in `except` blocks)\n* add [PT018] (checks for composite assertions)\n* add [PT019] (checks for fixtures without value injected as parameters)\n\n**1.0.0 - 2020-03-26**\n\n* add [PT014] (checks for duplicate test cases in `@pytest.mark.parametrize`)\n\n**0.6.0 - 2020-03-21**\n\n* add configuration option `pytest-parametrize-names-type` for [PT006]\n* add configuration options `pytest-parametrize-values-type` and\n`pytest-parametrize-values-row-type` for [PT007]\n\n**0.5.0 - 2020-03-09**\n\n* add configuration option `pytest-fixture-no-parentheses` for [PT001]\n* add [PT013] (checks for `from`-imports from `pytest`)\n\n**0.4.0 - 2020-03-09**\n\n* add [PT012] (checks for multiple statements in `with pytest.raises()`)\n\n**0.3.1 - 2020-03-09**\n\n* fix default value of `pytest-raises-require-match-for` config option\n\n**0.3.0 - 2020-03-09**\n\n* add [PT010] and [PT011] (checks for `pytest.raises` parameters)\n\n**0.2.0 - 2020-03-01**\n\n* add [PT009] (ported from [flake8-pytest](https://github.com/vikingco/flake8-pytest))\n\n**0.1.3 - 2019-05-24**\n\n* add `yield` fixtures support\n* fix changelog entry for 0.1.2\n\n**0.1.2 - 2019-05-23**\n\n* fix parametrize checkers not working in decorators\n\n**0.1.1 - 2019-05-23**\n\n* update PyPI description\n\n**0.1.0 - 2019-05-23**\n\n* initial\n\n[PT001]: /docs/rules/PT001.md\n[PT002]: /docs/rules/PT002.md\n[PT003]: /docs/rules/PT003.md\n[PT004]: /docs/rules/PT004.md\n[PT005]: /docs/rules/PT005.md\n[PT006]: /docs/rules/PT006.md\n[PT007]: /docs/rules/PT007.md\n[PT008]: /docs/rules/PT008.md\n[PT009]: /docs/rules/PT009.md\n[PT010]: /docs/rules/PT010.md\n[PT011]: /docs/rules/PT011.md\n[PT012]: /docs/rules/PT012.md\n[PT013]: /docs/rules/PT013.md\n[PT014]: /docs/rules/PT014.md\n[PT015]: /docs/rules/PT015.md\n[PT016]: /docs/rules/PT016.md\n[PT017]: /docs/rules/PT017.md\n[PT018]: /docs/rules/PT018.md\n[PT019]: /docs/rules/PT019.md\n[PT020]: /docs/rules/PT020.md\n[PT021]: /docs/rules/PT021.md\n[PT022]: /docs/rules/PT022.md\n[PT023]: /docs/rules/PT023.md\n[PT024]: /docs/rules/PT024.md\n[PT025]: /docs/rules/PT025.md\n[PT026]: /docs/rules/PT026.md\n[PT027]: /docs/rules/PT027.md\n[PT028]: /docs/rules/PT028.md\n[PT029]: /docs/rules/PT029.md\n[PT030]: /docs/rules/PT030.md\n[PT031]: /docs/rules/PT031.md\n"
  },
  {
    "path": "THIRD-PARTY-LICENSES",
    "content": "*******************************************************************************\nhttps://github.com/m-burst/cookiecutter-pypackage-poetry\n*******************************************************************************\n\nMIT License\n\nCopyright (c) 2019 Afonasev Evgeniy\nCopyright (c) 2019 Mikhail Burshteyn\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "docs/rules/PT001.md",
    "content": "# PT001\n\n`use @pytest.fixture over @pytest.fixture()`\n\n## Configuration\n\n* `pytest-fixture-no-parentheses`  \nBoolean flag specifying whether `@pytest.fixture()` without parameters\nshould have parentheses.  \nIf the option is set to true (the default), `@pytest.fixture` is valid\nand `@pytest.fixture()` is an error.  \nIf set to false, `@pytest.fixture()` is valid and `@pytest.fixture` is\nan error.\n\n## Examples\n\nBad code (assuming `pytest-fixture-no-parentheses` set to true):\n\n```python\nimport pytest\n\n@pytest.fixture()\ndef my_fixture():\n    ...\n```\n\nGood code:\n\n```python\nimport pytest\n\n@pytest.fixture\ndef my_fixture():\n    ...\n```\n\n## Rationale\n\n* to enforce consistency between all fixtures in a codebase\n"
  },
  {
    "path": "docs/rules/PT002.md",
    "content": "# PT002\n\n`configuration for fixture '{name}' specified via positional args, use kwargs`\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\n@pytest.fixture('module')\ndef my_fixture():\n    ...\n```\n\nGood code:\n\n```python\nimport pytest\n\n@pytest.fixture(scope='module')\ndef my_fixture():\n    ...\n```\n\n## Rationale\n\n* to make parameters meaning more obvious\n* to enforce consistency between all fixtures in a codebase\n"
  },
  {
    "path": "docs/rules/PT003.md",
    "content": "# PT003\n\n`scope='function' is implied in @pytest.fixture()`\n\nFixtures with function scope should not specify scope explicitly because\nfunction scope is implied by default.\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\n@pytest.fixture(scope='function')\ndef my_fixture():\n    ...\n```\n\nGood code:\n\n```python\nimport pytest\n\n@pytest.fixture()\ndef my_fixture():\n    ...\n```\n\n## Rationale\n\n* to enforce consistency between all fixtures in a codebase\n"
  },
  {
    "path": "docs/rules/PT004.md",
    "content": "# PT004\n\n`fixture '{name}' does not return anything, add leading underscore`\n\nThis rule does not fire on abstract fixtures (those decorated with `@abc.abstractmethod`),\nso that only the actual fixture implementations will be checked.\n\nThis rule also does not fire on fixtures containing `yield from`, because there is\nno reasonable way to determine whether the generator yields a value.\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\n@pytest.fixture()\ndef patch_something(mocker):\n    mocker.patch('module.object')\n\n@pytest.fixture()\ndef use_context():\n    with create_context():\n        yield\n```\n\nGood code:\n\n```python\nimport pytest\n\n@pytest.fixture()\ndef _patch_something(mocker):\n    mocker.patch('module.object')\n\n@pytest.fixture()\ndef _use_context():\n    with create_context():\n        yield\n```\n\n## Rationale\n\n* to enforce a naming convention for fixtures:\nfixtures that don't return a value start with a leading underscore (e.g. `_patch_something`),\nfixtures that return a value don't start with a leading underscore (e.g. `some_object`)\n\nSee also [PT005](PT005.md).\n"
  },
  {
    "path": "docs/rules/PT005.md",
    "content": "# PT005\n\n`fixture '{name}' returns a value, remove leading underscore`\n\nThis rule does not fire on abstract fixtures (those decorated with `@abc.abstractmethod`),\nso that only the actual fixture implementations will be checked.\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\n@pytest.fixture()\ndef _some_object():\n    return SomeClass()\n\n@pytest.fixture()\ndef _some_object_with_cleanup():\n    obj = SomeClass()\n    yield obj\n    obj.cleanup()\n```\n\nGood code:\n\n```python\nimport pytest\n\n@pytest.fixture()\ndef some_object():\n    return SomeClass()\n\n@pytest.fixture()\ndef some_object_with_cleanup():\n    obj = SomeClass()\n    yield obj\n    obj.cleanup()\n```\n\n## Rationale\n\n* to enforce a naming convention for fixtures:\nfixtures that don't return a value start with a leading underscore (e.g. `_patch_something`),\nfixtures that return a value don't start with a leading underscore (e.g. `some_object`)\n\nSee also [PT004](PT004.md).\n"
  },
  {
    "path": "docs/rules/PT006.md",
    "content": "# PT006\n\n`wrong name(s) type in @pytest.mark.parametrize, expected {expected_type}`\n\nFor a single name the expected type is always a plain string.\nFor multiple names the expected type is controlled by the configuration\nvariable `pytest-parametrize-names-type`.\n\n## Configuration\n\n* `pytest-parametrize-names-type`  \nExpected type for multiple argument names in `@pytest.mark.parametrize`.\nThe following values are supported:\n  * `csv` &mdash; a comma-separated list, e.g. `@pytest.mark.parametrize('name1,name2', ...)`\n  * `tuple` (default) &mdash; e.g. `@pytest.mark.parametrize(('name1', 'name2'), ...)`\n  * `list` &mdash; e.g. `@pytest.mark.parametrize(['name1', 'name2'], ...)`\n\n## Examples\n\nBad code (assuming `pytest-parametrize-names-type` is set to `tuple`):\n\n```python\nimport pytest\n\n# single parameter, always expecting string\n@pytest.mark.parametrize(('param', ), [1, 2, 3])\ndef test_foo(param):\n    ...\n\n# multiple parameters, expecting tuple due to settings\n@pytest.mark.parametrize(['param1', 'param2'], [(1, 2), (3, 4)])\ndef test_bar(param1, param2):\n    ...\n\n# multiple parameters, expecting tuple due to settings\n@pytest.mark.parametrize('param1,param2', [(1, 2), (3, 4)])\ndef test_baz(param1, param2):\n    ...\n```\n\nGood code:\n\n```python\nimport pytest\n\n@pytest.mark.parametrize('param', [1, 2, 3])\ndef test_foo(param):\n    ...\n\n@pytest.mark.parametrize(('param1', 'param2'), [(1, 2), (3, 4)])\ndef test_bar(param1, param2):\n    ...\n```\n\n## Rationale\n\n* to enforce consistency between all tests in a codebase\n"
  },
  {
    "path": "docs/rules/PT007.md",
    "content": "# PT007\n\n`wrong values type in @pytest.mark.parametrize, expected {expected_type}`\n\nThe expected type of the list of rows is controlled by the configuration\nvariable `pytest-parametrize-values-type`. The expected type of each row in\ncase of multiple arguments is controlled by the configuration variable\n`pytest-parametrize-values-row-type`.\n\n## Configuration\n\n* `pytest-parametrize-values-type`  \nExpected type for the list of values rows in `@pytest.mark.parametrize`.\nThe following values are supported:\n  * `tuple` &mdash; e.g. `@pytest.mark.parametrize('name', (1, 2, 3))`\n  * `list` (default) &mdash; e.g. `@pytest.mark.parametrize('name', [1, 2, 3])`\n\n* `pytest-parametrize-values-row-type`  \nExpected type for each row of values in `@pytest.mark.parametrize` in case of\nmultiple parameters. The following values are supported:\n  * `tuple` (default) &mdash; e.g. `@pytest.mark.parametrize(('name1', 'name2'), [(1, 2), (3, 4)])`\n  * `list` &mdash; e.g. `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], [3, 4]])`\n\n## Examples\n\nBad code (assuming `pytest-parametrize-values-type` set to `list` and\n`pytest-parametrize-values-row-type` set to `tuple`):\n\n```python\nimport pytest\n\n# expected list, got tuple\n@pytest.mark.parametrize('param', (1, 2))\ndef test_foo(param):\n    ...\n\n# expected top-level list, got tuple\n@pytest.mark.parametrize(\n    ('param1', 'param2'),\n    (\n        (1, 2),\n        (3, 4),\n    ),\n)\ndef test_bar(param1, param2):\n    ...\n\n# expected individual rows to be tuples, got lists\n@pytest.mark.parametrize(\n    ('param1', 'param2'),\n    [\n        [1, 2],\n        [3, 4],\n    ],\n)\ndef test_baz(param1, param2):\n    ...\n```\n\n```python\nimport pytest\n\n@pytest.mark.parametrize('param', [1, 2])\ndef test_foo(param):\n    ...\n\n@pytest.mark.parametrize(\n    ('param1', 'param2'),\n    [\n        (1, 2),\n        (3, 4),\n    ],\n)\ndef test_bar(param1, param2):\n    ...\n```\n\n## Rationale\n\n* to enforce consistency between all tests in a codebase\n"
  },
  {
    "path": "docs/rules/PT008.md",
    "content": "# PT008\n\n`use return_value= instead of patching with lambda`\n\nThis checks calls to `unittest.mock.patch` from standard library,\nas well as `mocker`, `session_mocker` etc. fixtures from\n[`pytest-mock`](https://pypi.org/project/pytest-mock/) library.\n\ne.g. `mocker.patch('target', return_value=7)` is OK, and `mocker.patch('target', lambda *args: 7)` is an error\n\n## Examples\n\nBad code:\n\n```python\ndef test_foo(mocker):\n    mocker.patch('module.target', lambda x, y: 7)\n```\n\nGood code:\n\n```python\ndef test_foo(mocker):\n    mocker.patch('module.target', return_value=7)\n    # if lambda parameters are used, it's not a violation\n    mocker.patch('module.other_target', lambda x, y: x)\n```\n\n## Rationale\n\n* this style of patching allows to use all mock functionality, such as checking\nthe list of calls to the patched function:\n  ```python\n  def test_foo(mocker):\n      mock_target = mocker.patch('module.target', return_value=7)\n      do_something()\n      mock_target.assert_called_once()\n  ```\n"
  },
  {
    "path": "docs/rules/PT009.md",
    "content": "# PT009\n\n`use a regular assert instead of unittest-style '{assertion}'`\n\n## Examples\n\nBad code:\n\n```python\nimport unittest\n\nclass TestFoo(unittest.TestCase):\n    def test_foo(self):\n        self.assertEqual(a, b)\n```\n\nGood code:\n\n```python\nimport unittest\n\nclass TestFoo(unittest.TestCase):\n    def test_foo(self):\n        assert a == b\n```\n\n## Rationale\n\n* to enforce the assertion style recommended by pytest\n* to make use of pytest's assertion rewriting\n"
  },
  {
    "path": "docs/rules/PT010.md",
    "content": "# PT010\n\n`set the expected exception in pytest.raises()`\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\ndef test_foo():\n    with pytest.raises():\n        do_something()\n```\n\nGood code:\n\n```python\nimport pytest\n\ndef test_foo():\n    with pytest.raises(SomeException):\n        do_something()\n```\n\n\n## Rationale\n\n* not passing the exception class will fail at runtime\n"
  },
  {
    "path": "docs/rules/PT011.md",
    "content": "# PT011\n\n`pytest.raises({exception}) is too broad, set the match parameter or use a more specific exception`\n\n## Configuration\n\n* `pytest-raises-require-match-for`  \nComma-separated list of exception names that require a `match=` parameter\nin a `pytest.raises()` call. By default the list contains the following\nexceptions:\n  * `BaseException`, `Exception`\n  * `ValueError`\n  * `OSError`, `IOError`, `EnvironmentError`, `socket.error`\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\ndef test_foo():\n    with pytest.raises(ValueError):\n        ...\n\n    # empty string is also an error\n    with pytest.raises(ValueError, match=''):\n        ...\n```\n\nGood code:\n\n```python\nimport pytest\n\ndef test_foo():\n    with pytest.raises(ValueError, match='expected message'):\n        ...\n```\n\n## Rationale\n\n* to help ensure that the `pytest.raises` clause is not too broad\n"
  },
  {
    "path": "docs/rules/PT012.md",
    "content": "# PT012\n\n`pytest.raises() block should contain a single simple statement`\n\nThis forbids multiple statements and control flow structures within\n`pytest.raises()` blocks.\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\ndef test_foo():\n    with pytest.raises(MyException):\n        # if get_object() raises MyException, the test is incorrect\n        obj = get_object()\n        obj.do_something()\n\n    with pytest.raises(MyException):\n        if some_condition:\n            do_something()\n```\n\nGood code:\n\n```python\nimport pytest\n\ndef test_foo():\n    obj = get_object()\n    with pytest.raises(MyException):\n        obj.do_something()\n```\n\nAn empty `with`-statement (containing only a `pass` inside) is allowed\nin order to allow testing of exceptions raised by context manager enter/exit methods.\n```python\nimport pytest\n\ndef test_my_context_manager():\n    context_manager = get_context_manager()\n    with pytest.raises(MyException):\n        with context_manager:\n            pass\n```\n\n## Rationale\n\n* to help ensure that only the expected exception from code under test is\ncaught in a `pytest.raises` block (e.g. not an exception from\ninitialization/finalization code)\n"
  },
  {
    "path": "docs/rules/PT013.md",
    "content": "# PT013\n\n`found incorrect import of pytest, use simple 'import pytest' instead`\n\n## Examples\n\nBad code:\n\n```python\nimport pytest as pt\nfrom pytest import fixture\n```\n\nGood code:\n\n```python\nimport pytest\n```\n\n## Rationale\n\n* to enforce consistency\n* to help the linter check usage of members imported from `pytest`\n"
  },
  {
    "path": "docs/rules/PT014.md",
    "content": "# PT014\n\n`found duplicate test cases {indexes} in @pytest.mark.parametrize`\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\n@pytest.mark.parametrize(\n    ('param1', 'param2'),\n    [\n        (1, 2),\n        (1, 2),\n    ]\n)\ndef test_foo(param1, param2):\n    ...\n```\n\n## Rationale\n\n* to help avoid duplicate test cases and accidental mistakes\n"
  },
  {
    "path": "docs/rules/PT015.md",
    "content": "# PT015\n\n`assertion always fails, replace with pytest.fail()`\n\n## Examples\n\nBad code:\n\n```python\ndef test_foo():\n    if some_condition:\n        assert False, 'some_condition was True'\n```\n\nGood code:\n\n```python\nimport pytest\n\ndef test_foo():\n    if some_condition:\n        pytest.fail('some_condition was True')\n```\n\n## Rationale\n\n* to enforce consistency across all tests in a codebase\n* to improve readability of test code and error messages\n"
  },
  {
    "path": "docs/rules/PT016.md",
    "content": "# PT016\n\n`no message passed to pytest.fail()`\n\nThe function `pytest.fail` must be called either with a positional argument,\na keyword argument `reason=` (since pytest version 7.0.0), or a keyword argument `msg=`\n(for compatibility with older versions of pytest).  Passing a keyword argument under a\nwrong name will also be reported as a violation.\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\ndef test_foo():\n    pytest.fail()\n\ndef test_bar():\n    pytest.fail('')\n\ndef test_baz():\n    pytest.fail(message='...')  # wrong kwarg name\n```\n\nGood code:\n\n```python\nimport pytest\n\ndef test_foo():\n    pytest.fail('...')\n\ndef test_bar():\n    pytest.fail(reason='...')\n\ndef test_baz():\n    pytest.fail(msg='...')\n```\n\n## Rationale\n\n* to make it easier to understand and debug test failures\n"
  },
  {
    "path": "docs/rules/PT017.md",
    "content": "# PT017\n\n`found assertion on exception {name} in except block, use pytest.raises() instead`\n\n## Examples\n\nBad code:\n\n```python\ndef test_foo():\n    try:\n        1 / 0\n    except ZeroDivisionError as e:\n        assert e.args\n```\n\nGood code:\n```python\nimport pytest\n\ndef test_foo():\n    with pytest.raises(ZeroDivisionError) as e:\n        1 / 0\n    assert e.value.args\n```\n\n## Rationale\n\n* to avoid the situations when the test incorrectly passes because exception\nwas not raised\n"
  },
  {
    "path": "docs/rules/PT018.md",
    "content": "# PT018\n\n`assertion should be broken down into multiple parts`\n\nThis violation is reported when the plugin encounter an assertion on multiple\nconditions.\n\n## Examples\n\nBad code:\n\n```python\ndef test_foo():\n    assert something and something_else\n\ndef test_bar():\n    assert not (something or something_else)\n```\n\nGood code:\n\n```python\ndef test_foo():\n    assert something\n    assert something_else\n\ndef test_bar():\n    assert not something\n    assert not something_else\n```\n\n## Rationale\n\n* to make it easier to understand and debug test failures\n"
  },
  {
    "path": "docs/rules/PT019.md",
    "content": "# PT019\n\n`fixture {name} without value is injected as parameter, use @pytest.mark.usefixtures instead`\n\n## Examples\n\nBad code:\n\n```python\ndef test_foo(_patch_something):\n    ...\n```\n\nGood code:\n```python\nimport pytest\n\n@pytest.mark.usefixtures('_patch_something')\ndef test_foo():\n    ...\n```\n\n## Rationale\n\n* to avoid unused parameters in test functions\n"
  },
  {
    "path": "docs/rules/PT020.md",
    "content": "# PT020\n\n`@pytest.yield_fixture is deprecated, use @pytest.fixture`\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\n@pytest.yield_fixture()\ndef my_fixture():\n    obj = SomeClass()\n    yield obj\n    obj.cleanup()\n```\n\nGood code:\n\n```python\nimport pytest\n\n@pytest.fixture()\ndef my_fixture():\n    obj = SomeClass()\n    yield obj\n    obj.cleanup()\n```\n\n## Rationale\n\n* to avoid using the deprecated function\n"
  },
  {
    "path": "docs/rules/PT021.md",
    "content": "# PT021\n\n`use yield instead of request.addfinalizer`\n\n`pytest` offers two ways to perform cleanup in fixture code.  One is sequential\n(`yield` statement), and the other is callback-based (`request.addfinalizer`).\n\n`request.addfinalizer` is allowed when implementing [Factories as fixtures] pattern,\nsee examples below for more details.\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\n@pytest.fixture()\ndef my_fixture(request):\n    resource = acquire_resource()\n    request.addfinalizer(resource.release)\n    return resource\n```\n\nGood code:\n```python\nimport pytest\n\n@pytest.fixture()\ndef my_fixture():\n    resource = acquire_resource()\n    yield resource\n    resource.release()\n\n# \"Factories as fixtures\" pattern\n@pytest.fixture()\ndef my_factory(request):\n    def create_resource(arg):\n        resource = acquire_resource(arg)\n        request.addfinalizer(resource.release)\n        return resource\n    return create_resource\n```\n\n## Rationale\n\n* to make fixture code more linear and straightforward\n\n[Factories as fixtures]: https://docs.pytest.org/en/stable/fixture.html#factories-as-fixtures\n"
  },
  {
    "path": "docs/rules/PT022.md",
    "content": "# PT022\n\n`no teardown in fixture {name}, use return instead of yield`\n\n`yield` in fixtures is only useful and semantically correct\nwhen the fixture contains some teardown code.\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\n@pytest.fixture()\ndef my_fixture():\n    resource = acquire_resource()\n    yield resource\n```\n\nGood code:\n```python\nimport pytest\n\n@pytest.fixture()\ndef my_fixture_with_teardown():\n    resource = acquire_resource()\n    yield resource\n    resource.release()\n\n@pytest.fixture()\ndef my_fixture_without_teardown():\n    resource = acquire_resource()\n    return resource\n```\n\n## Rationale\n\n* to make sure that all `yield` usages are semanticaly correct\n"
  },
  {
    "path": "docs/rules/PT023.md",
    "content": "# PT023\n\n`use @pytest.mark.foo over @pytest.mark.foo()`\n\n## Configuration\n\n* `pytest-mark-no-parentheses`  \nBoolean flag specifying whether `@pytest.mark.foo()` without parameters\nshould have parentheses.  \nIf the option is set to true (the default), `@pytest.mark.foo` is valid\nand `@pytest.mark.foo()` is an error.  \nIf set to false, `@pytest.mark.foo()` is valid and `@pytest.mark.foo` is\nan error.\n\n## Examples\n\nBad code (assuming `pytest-mark-no-parentheses` set to true):\n\n```python\nimport pytest\n\n@pytest.mark.foo()\ndef test_something():\n    ...\n```\n\nGood code:\n\n```python\nimport pytest\n\n@pytest.mark.foo\ndef test_something():\n    ...\n```\n\n## Rationale\n\n* to enforce consistency between all tests in a codebase\n"
  },
  {
    "path": "docs/rules/PT024.md",
    "content": "# PT024\n\n`pytest.mark.asyncio is unnecessary for fixtures`\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\n@pytest.mark.asyncio()\n@pytest.fixture()\nasync def my_fixture():\n    return 0\n```\n\nGood code:\n\n```python\nimport pytest\n\n@pytest.fixture()\nasync def my_fixture():\n    return 0\n```\n\n## Rationale\n\n* the mark is useless on fixtures and therefore unnecessary\n"
  },
  {
    "path": "docs/rules/PT025.md",
    "content": "# PT025\n\n`pytest.mark.usefixtures has no effect on fixtures`\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\n@pytest.fixture()\ndef a():\n  pass\n\n@pytest.mark.usefixtures('a')\n@pytest.fixture()\ndef b():\n  pass\n```\n\nGood code:\n\n```python\nimport pytest\n\n@pytest.fixture()\ndef a():\n  pass\n\n@pytest.fixture()\ndef b(a):\n  pass\n```\n\n## Rationale\n\n* according to the pytest [docs](https://docs.pytest.org/en/6.2.x/reference.html#pytest-mark-usefixtures)\n  on `pytest.mark.usefixtures`:\n   > Also note that this mark has no effect when applied to fixtures.\n* pytest does not raise any error or warning when fixtures are decorated with `pytest.mark.usefixtures`,\n  which can lead to incorrect results and broken tests"
  },
  {
    "path": "docs/rules/PT026.md",
    "content": "# PT023\n\n`useless pytest.mark.usefixtures without parameters`\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\n@pytest.mark.usefixtures()\ndef test_something():\n    ...\n\n@pytest.mark.usefixtures\ndef test_something_else():\n    ...\n```\n\nGood code:\n\n```python\nimport pytest\n\n@pytest.mark.usefixtures('a')\ndef test_something():\n    ...\n```\n\n## Rationale\n\n* such mark has no effect and is unnecessary\n"
  },
  {
    "path": "docs/rules/PT027.md",
    "content": "# PT027\n\n`use pytest.raises() instead of unittest-style '{assertion}'`\n\n## Examples\n\nBad code:\n\n```python\nimport unittest\n\nclass TestFoo(unittest.TestCase):\n    def test_foo(self):\n        with self.assertRaises(ValueError):\n            raise ValueError('foo')\n```\n\nGood code:\n\n```python\nimport pytest\nimport unittest\n\nclass TestFoo(unittest.TestCase):\n    def test_foo(self):\n        with pytest.raises(ValueError):\n            raise ValueError('foo')\n```\n\n## Rationale\n\n* to enforce the assertion style recommended by pytest\n"
  },
  {
    "path": "docs/rules/PT028.md",
    "content": "# PT028\n\n`test function {name} has default value for argument {arg}, remove it`\n\n## Examples\n\nBad code:\n\n```python\ndef test_foo(bar=42):\n    pass\n```\n\nGood code:\n\n```python\ndef test_foo(bar):\n    pass\n```\n\n## Rationale\n\n* even if the corresponding fixture is defined, current behavior of pytest is \n   to use the default value instead of injecting the fixture\n* see original pytest issue: https://github.com/pytest-dev/pytest#12693\n"
  },
  {
    "path": "docs/rules/PT029.md",
    "content": "# PT029\n\n`set the expected warning in pytest.warns()`\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\ndef test_foo():\n    with pytest.warns():\n        do_something()\n```\n\nGood code:\n\n```python\nimport pytest\n\ndef test_foo():\n    with pytest.warns(SomeWarning):\n        do_something()\n```\n\n\n## Rationale\n\n* not passing the warning class will fail at runtime\n"
  },
  {
    "path": "docs/rules/PT030.md",
    "content": "# PT030\n\n`pytest.warns({warning}) is too broad, set the match parameter or use a more specific warning`\n\n## Configuration\n\n* `pytest-warns-require-match-for`  \nComma-separated list of warning names that require a `match=` parameter\nin a `pytest.warning()` call. By default the list contains the following\nwarnings:\n  * `Warning`\n  * `UserWarning`\n  * `DeprecationWarning`\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\ndef test_foo():\n    with pytest.warns(UserWarning):\n        ...\n\n    # empty string is also an error\n    with pytest.warns(UserWarning, match=''):\n        ...\n```\n\nGood code:\n\n```python\nimport pytest\n\ndef test_foo():\n    with pytest.warns(UserWarning, match='expected message'):\n        ...\n```\n\n## Rationale\n\n* to help ensure that the `pytest.warns` clause is not too broad\n"
  },
  {
    "path": "docs/rules/PT031.md",
    "content": "# PT031\n\n`pytest.warns() block should contain a single simple statement`\n\nThis forbids multiple statements and control flow structures within\n`pytest.warns()` blocks.\n\n## Examples\n\nBad code:\n\n```python\nimport pytest\n\ndef test_foo():\n    with pytest.warns(MyWarning):\n        # if get_object() raises MyWarning, the test is incorrect\n        obj = get_object()\n        obj.do_something()\n\n    with pytest.warns(MyWarning):\n        if some_condition:\n            do_something()\n```\n\nGood code:\n\n```python\nimport pytest\n\ndef test_foo():\n    obj = get_object()\n    with pytest.warns(MyWarning):\n        obj.do_something()\n```\n\nAn empty `with`-statement (containing only a `pass` inside) is allowed\nin order to allow testing of warnings raised by context manager enter/exit methods.\n```python\nimport pytest\n\ndef test_my_context_manager():\n    context_manager = get_context_manager()\n    with pytest.warns(MyWarning):\n        with context_manager:\n            pass\n```\n\n## Rationale\n\n* to help ensure that only the expected warning from code under test is\ncaught in a `pytest.warns` block (e.g. not an warning from\ninitialization/finalization code)\n"
  },
  {
    "path": "flake8_pytest_style/__init__.py",
    "content": ""
  },
  {
    "path": "flake8_pytest_style/config.py",
    "content": "from enum import Enum\nfrom typing import Any, List, NamedTuple, Type\n\n\ndef enum_choices(enum: Type[Enum]) -> List[Any]:\n    return [member.value for member in enum]\n\n\nclass ParametrizeNamesType(Enum):\n    CSV = \"csv\"\n    TUPLE = \"tuple\"\n    LIST = \"list\"\n\n\nclass ParametrizeValuesType(Enum):\n    TUPLE = \"tuple\"\n    LIST = \"list\"\n\n\nclass ParametrizeValuesRowType(Enum):\n    TUPLE = \"tuple\"\n    LIST = \"list\"\n\n\nclass Config(NamedTuple):\n    fixture_parentheses: bool\n    raises_require_match_for: List[str]\n    warns_require_match_for: List[str]\n    parametrize_names_type: ParametrizeNamesType\n    parametrize_values_type: ParametrizeValuesType\n    parametrize_values_row_type: ParametrizeValuesRowType\n    mark_parentheses: bool\n\n\nDEFAULT_CONFIG = Config(\n    fixture_parentheses=False,\n    raises_require_match_for=[\n        \"BaseException\",\n        \"Exception\",\n        \"ValueError\",\n        \"IOError\",\n        \"OSError\",\n        \"EnvironmentError\",\n        \"socket.error\",\n    ],\n    warns_require_match_for=[\"Warning\", \"UserWarning\", \"DeprecationWarning\"],\n    parametrize_names_type=ParametrizeNamesType.TUPLE,\n    parametrize_values_type=ParametrizeValuesType.LIST,\n    parametrize_values_row_type=ParametrizeValuesRowType.TUPLE,\n    mark_parentheses=False,\n)\n"
  },
  {
    "path": "flake8_pytest_style/errors.py",
    "content": "from flake8_plugin_utils import Error\n\n\nclass IncorrectFixtureParenthesesStyle(Error):\n    code = \"PT001\"\n    message = \"use @pytest.fixture{expected_parens} over @pytest.fixture{actual_parens}\"\n\n\nclass FixturePositionalArgs(Error):\n    code = \"PT002\"\n    message = (\n        \"configuration for fixture '{name}' specified via positional args, use kwargs\"\n    )\n\n\nclass ExtraneousScopeFunction(Error):\n    code = \"PT003\"\n    message = \"scope='function' is implied in @pytest.fixture()\"\n\n\nclass MissingFixtureNameUnderscore(Error):\n    code = \"PT004\"\n    message = \"fixture '{name}' does not return anything, add leading underscore\"\n\n\nclass IncorrectFixtureNameUnderscore(Error):\n    code = \"PT005\"\n    message = \"fixture '{name}' returns a value, remove leading underscore\"\n\n\nclass ParametrizeNamesWrongType(Error):\n    code = \"PT006\"\n    message = \"wrong name(s) type in @pytest.mark.parametrize, expected {expected_type}\"\n\n\nclass ParametrizeValuesWrongType(Error):\n    code = \"PT007\"\n    message = \"wrong values type in @pytest.mark.parametrize, expected {expected_type}\"\n\n\nclass PatchWithLambda(Error):\n    code = \"PT008\"\n    message = \"use return_value= instead of patching with lambda\"\n\n\nclass UnittestAssertion(Error):\n    code = \"PT009\"\n    message = \"use a regular assert instead of unittest-style '{assertion}'\"\n\n\nclass RaisesWithoutException(Error):\n    code = \"PT010\"\n    message = \"set the expected exception in pytest.raises()\"\n\n\nclass RaisesTooBroad(Error):\n    code = \"PT011\"\n    message = (\n        \"pytest.raises({exception}) is too broad,\"\n        \" set the match parameter or use a more specific exception\"\n    )\n\n\nclass RaisesWithMultipleStatements(Error):\n    code = \"PT012\"\n    message = \"pytest.raises() block should contain a single simple statement\"\n\n\nclass IncorrectPytestImport(Error):\n    code = \"PT013\"\n    message = \"found incorrect import of pytest, use simple 'import pytest' instead\"\n\n\nclass DuplicateParametrizeTestCases(Error):\n    code = \"PT014\"\n    message = \"found duplicate test cases {indexes} in @pytest.mark.parametrize\"\n\n\nclass AssertAlwaysFalse(Error):\n    code = \"PT015\"\n    message = \"assertion always fails, replace with pytest.fail()\"\n\n\nclass FailWithoutMessage(Error):\n    code = \"PT016\"\n    message = \"no message passed to pytest.fail()\"\n\n\nclass AssertInExcept(Error):\n    code = \"PT017\"\n    message = (\n        \"found assertion on exception {name} in except block,\"\n        \" use pytest.raises() instead\"\n    )\n\n\nclass CompositeAssertion(Error):\n    code = \"PT018\"\n    message = \"assertion should be broken down into multiple parts\"\n\n\nclass FixtureParamWithoutValue(Error):\n    code = \"PT019\"\n    message = (\n        \"fixture {name} without value is injected as parameter,\"\n        \" use @pytest.mark.usefixtures instead\"\n    )\n\n\nclass DeprecatedYieldFixture(Error):\n    code = \"PT020\"\n    message = \"@pytest.yield_fixture is deprecated, use @pytest.fixture\"\n\n\nclass FixtureFinalizerCallback(Error):\n    code = \"PT021\"\n    message = \"use yield instead of request.addfinalizer\"\n\n\nclass UselessYieldFixture(Error):\n    code = \"PT022\"\n    message = \"no teardown in fixture {name}, use return instead of yield\"\n\n\nclass IncorrectMarkParenthesesStyle(Error):\n    code = \"PT023\"\n    message = (\n        \"use @pytest.mark.{mark_name}{expected_parens}\"\n        \" over @pytest.mark.{mark_name}{actual_parens}\"\n    )\n\n\nclass UnnecessaryAsyncioMarkOnFixture(Error):\n    code = \"PT024\"\n    message = \"pytest.mark.asyncio is unnecessary for fixtures\"\n\n\nclass ErroneousUseFixturesOnFixture(Error):\n    code = \"PT025\"\n    message = \"pytest.mark.usefixtures has no effect on fixtures\"\n\n\nclass UseFixturesWithoutParameters(Error):\n    code = \"PT026\"\n    message = \"useless pytest.mark.usefixtures without parameters\"\n\n\nclass UnittestRaisesAssertion(Error):\n    code = \"PT027\"\n    message = \"use pytest.raises() instead of unittest-style '{assertion}'\"\n\n\n# This should be named `TestFunctionArgumentWithDefault`,\n# but this way it is easier to avoid confusion with the `Test` prefix in pytest.\nclass TFunctionArgumentWithDefault(Error):\n    code = \"PT028\"\n    message = \"test function {name} has default value for argument {arg}, remove it\"\n\n\nclass WarnsWithoutException(Error):\n    code = \"PT029\"\n    message = \"set the expected warning in pytest.warns()\"\n\n\nclass WarnsTooBroad(Error):\n    code = \"PT030\"\n    message = (\n        \"pytest.warns({warning}) is too broad,\"\n        \" set the match parameter or use a more specific warning\"\n    )\n\n\nclass WarnsWithMultipleStatements(Error):\n    code = \"PT031\"\n    message = \"pytest.warns() block should contain a single simple statement\"\n"
  },
  {
    "path": "flake8_pytest_style/plugin.py",
    "content": "import argparse\nfrom typing import List\n\nfrom flake8.options.manager import OptionManager\nfrom flake8_plugin_utils import Plugin\n\nfrom .config import (\n    DEFAULT_CONFIG,\n    Config,\n    ParametrizeNamesType,\n    ParametrizeValuesRowType,\n    ParametrizeValuesType,\n    enum_choices,\n)\nfrom .visitors import (\n    AssertionVisitor,\n    FailVisitor,\n    FixturesVisitor,\n    ImportsVisitor,\n    MarksVisitor,\n    ParametrizeVisitor,\n    PatchVisitor,\n    RaisesVisitor,\n    TFunctionsVisitor,\n    TryExceptVisitor,\n    UnittestAssertionVisitor,\n    WarnsVisitor,\n)\n\n__version__ = \"2.2.0\"\n\n\nclass PytestStylePlugin(Plugin[Config]):\n    name = \"flake8-pytest-style\"\n    version = __version__\n    visitors = [\n        AssertionVisitor,\n        FailVisitor,\n        FixturesVisitor,\n        ImportsVisitor,\n        MarksVisitor,\n        PatchVisitor,\n        ParametrizeVisitor,\n        RaisesVisitor,\n        TFunctionsVisitor,\n        TryExceptVisitor,\n        UnittestAssertionVisitor,\n        WarnsVisitor,\n    ]\n\n    @classmethod\n    def add_options(cls, option_manager: OptionManager) -> None:\n        option_manager.add_option(\n            \"--pytest-fixture-no-parentheses\",\n            action=\"store_true\",\n            parse_from_config=True,\n            default=not DEFAULT_CONFIG.fixture_parentheses,\n            help=\"Omit parentheses for @pytest.fixture decorators\"\n            \" without parameters. (Default: %(default)s)\",\n        )\n        option_manager.add_option(\n            \"--pytest-raises-require-match-for\",\n            comma_separated_list=True,\n            parse_from_config=True,\n            default=DEFAULT_CONFIG.raises_require_match_for,\n            help=\"List of exceptions for which flake8-pytest-style requires\"\n            \" a match= argument in pytest.raises(). (Default: %(default)s)\",\n        )\n        option_manager.add_option(\n            \"--pytest-parametrize-names-type\",\n            choices=enum_choices(ParametrizeNamesType),\n            parse_from_config=True,\n            default=DEFAULT_CONFIG.parametrize_names_type.value,\n            help=\"Preferred type for multiple parameter names in\"\n            \" @pytest.mark.parametrize. (Default: %(default)s)\",\n        )\n        option_manager.add_option(\n            \"--pytest-parametrize-values-type\",\n            choices=enum_choices(ParametrizeValuesType),\n            parse_from_config=True,\n            default=DEFAULT_CONFIG.parametrize_values_type.value,\n            help=\"Preferred type for values in @pytest.mark.parametrize.\"\n            \" (Default: %(default)s)\",\n        )\n        option_manager.add_option(\n            \"--pytest-parametrize-values-row-type\",\n            choices=enum_choices(ParametrizeValuesRowType),\n            parse_from_config=True,\n            default=DEFAULT_CONFIG.parametrize_values_row_type.value,\n            help=\"Preferred type for each row in @pytest.mark.parametrize\"\n            \" in case of multiple parameters. (Default: %(default)s)\",\n        )\n        option_manager.add_option(\n            \"--pytest-mark-no-parentheses\",\n            action=\"store_true\",\n            parse_from_config=True,\n            default=not DEFAULT_CONFIG.mark_parentheses,\n            help=\"Omit parentheses for @pytest.mark.foo decorators\"\n            \" without parameters. (Default: %(default)s)\",\n        )\n        option_manager.add_option(\n            \"--pytest-warns-require-match-for\",\n            comma_separated_list=True,\n            parse_from_config=True,\n            default=DEFAULT_CONFIG.warns_require_match_for,\n            help=\"List of warnings for which flake8-pytest-style requires\"\n            \" a match= argument in pytest.warns(). (Default: %(default)s)\",\n        )\n\n    @classmethod\n    def parse_options_to_config(  # pylint: disable=unused-argument\n        cls, option_manager: OptionManager, options: argparse.Namespace, args: List[str]\n    ) -> Config:\n        return Config(\n            fixture_parentheses=not options.pytest_fixture_no_parentheses,\n            raises_require_match_for=options.pytest_raises_require_match_for,\n            parametrize_names_type=ParametrizeNamesType(\n                options.pytest_parametrize_names_type\n            ),\n            parametrize_values_type=ParametrizeValuesType(\n                options.pytest_parametrize_values_type\n            ),\n            parametrize_values_row_type=ParametrizeValuesRowType(\n                options.pytest_parametrize_values_row_type\n            ),\n            mark_parentheses=not options.pytest_mark_no_parentheses,\n            warns_require_match_for=options.pytest_warns_require_match_for,\n        )\n"
  },
  {
    "path": "flake8_pytest_style/py.typed",
    "content": ""
  },
  {
    "path": "flake8_pytest_style/utils.py",
    "content": "import ast\nfrom collections import deque\nfrom typing import Dict, Iterator, List, NamedTuple, Optional, Tuple, Union\n\nAnyFunctionDef = Union[ast.AsyncFunctionDef, ast.FunctionDef]\nAnyDecoratorTarget = Union[ast.ClassDef, AnyFunctionDef]\n\n\ndef get_qualname(node: ast.AST) -> Optional[str]:\n    \"\"\"\n    If node represents a chain of attribute accesses, return is qualified name.\n    \"\"\"\n    parts = []\n    while True:\n        if isinstance(node, ast.Name):\n            parts.append(node.id)\n            break\n        if isinstance(node, ast.Attribute):\n            parts.append(node.attr)\n            node = node.value\n        else:\n            return None\n    return \".\".join(reversed(parts))\n\n\nclass SimpleCallArgs(NamedTuple):\n    args: Tuple[ast.AST, ...]\n    kwargs: Dict[str, ast.AST]\n\n    def get_argument(\n        self, name: str, position: Optional[int] = None\n    ) -> Optional[ast.AST]:\n        \"\"\"Get argument by name in kwargs or position in args.\"\"\"\n        kwarg = self.kwargs.get(name)\n        if kwarg is not None:\n            return kwarg\n        if position is not None and len(self.args) > position:\n            return self.args[position]\n        return None\n\n\ndef get_simple_call_args(node: ast.Call) -> SimpleCallArgs:\n    \"\"\"\n    Get call arguments which are specified explicitly (positional and keyword).\n    \"\"\"\n\n    # list of leading non-starred args\n    args = []\n    for arg in node.args:\n        if isinstance(arg, ast.Starred):\n            break\n        args.append(arg)\n\n    # dict of keyword args\n    keywords: Dict[str, ast.AST] = {}\n    for keyword in node.keywords:\n        if keyword.arg is not None:\n            keywords[keyword.arg] = keyword.value\n\n    return SimpleCallArgs(tuple(args), keywords)\n\n\ndef is_parametrize_call(node: ast.Call) -> bool:\n    \"\"\"Checks if given call is to `pytest.mark.parametrize`.\"\"\"\n    return get_qualname(node.func) == \"pytest.mark.parametrize\"\n\n\ndef is_raises_call(node: ast.Call) -> bool:\n    \"\"\"Checks if given call is to `pytest.raises`.\"\"\"\n    return get_qualname(node.func) == \"pytest.raises\"\n\n\ndef is_warns_call(node: ast.Call) -> bool:\n    \"\"\"Checks if given call is to `pytest.warns`.\"\"\"\n    return get_qualname(node.func) == \"pytest.warns\"\n\n\ndef is_fail_call(node: ast.Call) -> bool:\n    \"\"\"Checks if given call is to `pytest.fail`.\"\"\"\n    return get_qualname(node.func) == \"pytest.fail\"\n\n\ndef is_raises_with(node: ast.With) -> bool:\n    \"\"\"Checks that a given `with` statement has a `pytest.raises` context.\"\"\"\n    for item in node.items:\n        if isinstance(item.context_expr, ast.Call) and is_raises_call(\n            item.context_expr\n        ):\n            return True\n    return False\n\n\ndef is_warns_with(node: ast.With) -> bool:\n    \"\"\"Checks that a given `with` statement has a `pytest.warns` context.\"\"\"\n    for item in node.items:\n        if isinstance(item.context_expr, ast.Call) and is_warns_call(item.context_expr):\n            return True\n    return False\n\n\nclass ParametrizeArgs(NamedTuple):\n    names: ast.AST\n    values: Optional[ast.AST]\n    ids: Optional[ast.AST]\n\n\ndef extract_parametrize_call_args(node: ast.Call) -> Optional[ParametrizeArgs]:\n    \"\"\"Extracts argnames, argvalues and ids from a parametrize call.\"\"\"\n    args = get_simple_call_args(node)\n\n    names_arg = args.get_argument(\"argnames\", 0)\n    if names_arg is None:\n        return None\n\n    values_arg = args.get_argument(\"argvalues\", 1)\n    ids_arg = args.get_argument(\"ids\")\n    return ParametrizeArgs(names_arg, values_arg, ids_arg)\n\n\ndef _is_pytest_fixture(node: ast.AST) -> bool:\n    \"\"\"Checks if node is a `pytest.fixture` attribute access.\"\"\"\n    return get_qualname(node) == \"pytest.fixture\"\n\n\ndef is_pytest_yield_fixture(node: ast.AST) -> bool:\n    \"\"\"Checks if node is a `pytest.yield_fixture` attribute access.\"\"\"\n    return get_qualname(node) == \"pytest.yield_fixture\"\n\n\ndef _is_any_pytest_fixture(node: ast.AST) -> bool:\n    \"\"\"Checks if node is a `pytest.fixture` or `pytest.yield_fixture`.\"\"\"\n    return _is_pytest_fixture(node) or is_pytest_yield_fixture(node)\n\n\ndef get_fixture_decorator(node: AnyFunctionDef) -> Union[ast.Call, ast.Attribute, None]:\n    \"\"\"\n    Returns a @pytest.fixture decorator applied to given function definition, if any.\n\n    Return value is either:\n    * ast.Call, if decorator is written as @pytest.fixture()\n    * ast.Attribute, if decorator is written as @pytest.fixture\n    * None, if decorator not found\n    \"\"\"\n    for decorator in node.decorator_list:\n        if (\n            isinstance(decorator, ast.Call)\n            and isinstance(decorator.func, ast.Attribute)\n            and _is_any_pytest_fixture(decorator.func)\n        ):\n            return decorator\n        if isinstance(decorator, ast.Attribute) and _is_any_pytest_fixture(decorator):\n            return decorator\n\n    return None\n\n\ndef _is_mark(node: ast.AST) -> bool:\n    \"\"\"Checks if node is a `pytest.mark.foo` attribute access.\"\"\"\n    qualname = get_qualname(node)\n    if qualname is None:\n        return False\n    return qualname.startswith(\"pytest.mark.\")\n\n\ndef get_mark_decorators(\n    node: AnyDecoratorTarget,\n) -> List[Union[ast.Call, ast.Attribute]]:\n    \"\"\"\n    Returns all @pytest.mark.foo decorators applied to given function definition.\n\n    Return value is a list of:\n    * ast.Call, if decorator is written as @pytest.mark.foo()\n    * ast.Attribute, if decorator is written as @pytest.mark.foo\n    \"\"\"\n    result: List[Union[ast.Call, ast.Attribute]] = []\n    for decorator in node.decorator_list:\n        if (\n            isinstance(decorator, ast.Call)\n            and isinstance(decorator.func, ast.Attribute)\n            and _is_mark(decorator.func)\n        ):\n            result.append(decorator)\n        if isinstance(decorator, ast.Attribute) and _is_mark(decorator):\n            result.append(decorator)\n    return result\n\n\ndef get_mark_name(node: ast.AST) -> str:\n    \"\"\"\n    Returns the name of the mark in a `pytest.mark.foo` attribute access\n    or in a `pytest.mark.foo()` call.\n\n    If the given node is not suitable as described above, a ValueError is raised.\n    \"\"\"\n    mark_prefix = \"pytest.mark.\"\n    if isinstance(node, ast.Call):\n        node = node.func\n    qualname = get_qualname(node)\n    if qualname is None or not qualname.startswith(mark_prefix):\n        raise ValueError(\"Given node is not a pytest mark\")\n    return qualname[len(mark_prefix) :]  # noqa: E203\n\n\ndef is_none(node: ast.AST) -> bool:\n    \"\"\"\n    Checks if the node is a constant representing the value `None`.\n\n    Drop-in replacement for `flake8_plugin_utils.utils.is_none` without using\n    removed `ast.NameConstant` class.\n    \"\"\"\n\n    return isinstance(node, ast.Constant) and node.value is None\n\n\ndef is_empty_string(node: ast.AST) -> bool:\n    \"\"\"\n    Checks if the node is a constant empty string.\n    \"\"\"\n\n    # empty string literal\n    if isinstance(node, ast.Constant) and node.value == \"\":\n        return True\n\n    # empty f-string\n    if isinstance(node, ast.JoinedStr) and not node.values:\n        return True\n\n    return False\n\n\ndef _is_empty_iterable(  # pylint:disable=too-many-return-statements\n    node: ast.AST,\n) -> bool:\n    \"\"\"\n    Checks if the node is a constant empty iterable.\n    \"\"\"\n\n    if is_empty_string(node):\n        return True\n\n    # empty list or tuple literal\n    if isinstance(node, (ast.List, ast.Tuple)) and not node.elts:\n        return True\n\n    # empty dict literal\n    if isinstance(node, ast.Dict) and not node.keys:\n        return True\n\n    if isinstance(node, ast.Call) and get_qualname(node.func) in (\n        \"list\",\n        \"set\",\n        \"tuple\",\n        \"dict\",\n        \"frozenset\",\n    ):\n        if not node.args and not node.keywords:  # no args\n            return True\n        if (\n            len(node.args) == 1\n            and not node.keywords\n            and _is_empty_iterable(node.args[0])\n        ):  # single arg, empty iterable\n            return True\n\n    return False\n\n\ndef is_falsy_constant(node: ast.AST) -> bool:\n    \"\"\"\n    Checks if the node is a constant with a falsy value.\n    \"\"\"\n\n    # constant node: None, False, zero, empty string (not f-string)\n    if isinstance(node, ast.Constant) and not node.value:\n        return True\n\n    return _is_empty_iterable(node)\n\n\ndef is_test_function(node: AnyFunctionDef) -> bool:\n    \"\"\"Checks if the given function is a test function.\"\"\"\n    return node.name.startswith(\"test_\")\n\n\ndef get_all_argument_names(node: ast.arguments) -> List[str]:\n    \"\"\"Returns a list of all argument names from the given node.\"\"\"\n    pos_only_args = getattr(node, \"posonlyargs\", [])\n    result = [arg.arg for arg in pos_only_args + node.args]\n    if node.vararg:\n        result.append(node.vararg.arg)\n    result.extend([arg.arg for arg in node.kwonlyargs])\n    if node.kwarg:\n        result.append(node.kwarg.arg)\n    return result\n\n\ndef walk_without_nested_functions(root: ast.AST) -> Iterator[ast.AST]:\n    \"\"\"Similar to `ast.walk`, but does not descend into nested functions.\"\"\"\n\n    todo = deque([root])\n    while todo:\n        node = todo.popleft()\n        if node is root or not isinstance(\n            node, (ast.FunctionDef, ast.AsyncFunctionDef)\n        ):\n            todo.extend(ast.iter_child_nodes(node))\n        yield node\n\n\ndef is_abstract_method(node: AnyFunctionDef) -> bool:\n    \"\"\"\n    Returns true if the node is decorated with an abstract method decorator,\n    otherwise false.\n    \"\"\"\n    for decorator in node.decorator_list:\n        qualname = get_qualname(decorator)\n        if qualname in (\"abstractmethod\", \"abc.abstractmethod\"):\n            return True\n    return False\n\n\ndef is_nontrivial_with_statement(node: ast.AST) -> bool:\n    \"\"\"\n    Returns true if the given node is a `with` (or `async with`) statement\n    containing any code inside (anything which is not a single `pass` statement).\n    \"\"\"\n    if not isinstance(node, (ast.With, ast.AsyncWith)):\n        return False\n    body = node.body\n    return len(node.body) != 1 or not isinstance(body[0], ast.Pass)\n"
  },
  {
    "path": "flake8_pytest_style/visitors/__init__.py",
    "content": "from .assertion import AssertionVisitor, UnittestAssertionVisitor\nfrom .fail import FailVisitor\nfrom .fixtures import FixturesVisitor\nfrom .imports import ImportsVisitor\nfrom .marks import MarksVisitor\nfrom .parametrize import ParametrizeVisitor\nfrom .patch import PatchVisitor\nfrom .raises import RaisesVisitor\nfrom .t_functions import TFunctionsVisitor\nfrom .try_except import TryExceptVisitor\nfrom .warns import WarnsVisitor\n\n__all__ = (\n    \"AssertionVisitor\",\n    \"FailVisitor\",\n    \"FixturesVisitor\",\n    \"ImportsVisitor\",\n    \"MarksVisitor\",\n    \"ParametrizeVisitor\",\n    \"PatchVisitor\",\n    \"RaisesVisitor\",\n    \"TFunctionsVisitor\",\n    \"TryExceptVisitor\",\n    \"UnittestAssertionVisitor\",\n    \"WarnsVisitor\",\n)\n"
  },
  {
    "path": "flake8_pytest_style/visitors/assertion.py",
    "content": "import ast\n\nfrom flake8_plugin_utils import Visitor\n\nfrom flake8_pytest_style.config import Config\nfrom flake8_pytest_style.errors import (\n    CompositeAssertion,\n    UnittestAssertion,\n    UnittestRaisesAssertion,\n)\n\n_UNITTEST_ASSERT_NAMES = (\n    # taken from dir(unittest.TestCase) under Python 3.11\n    \"assertAlmostEqual\",\n    \"assertAlmostEquals\",\n    \"assertCountEqual\",\n    \"assertDictContainsSubset\",\n    \"assertDictEqual\",\n    \"assertEqual\",\n    \"assertEquals\",\n    \"assertFalse\",\n    \"assertGreater\",\n    \"assertGreaterEqual\",\n    \"assertIn\",\n    \"assertIs\",\n    \"assertIsInstance\",\n    \"assertIsNone\",\n    \"assertIsNot\",\n    \"assertIsNotNone\",\n    \"assertLess\",\n    \"assertLessEqual\",\n    \"assertListEqual\",\n    \"assertLogs\",\n    \"assertMultiLineEqual\",\n    \"assertNoLogs\",\n    \"assertNotAlmostEqual\",\n    \"assertNotAlmostEquals\",\n    \"assertNotEqual\",\n    \"assertNotEquals\",\n    \"assertNotIn\",\n    \"assertNotIsInstance\",\n    \"assertNotRegex\",\n    \"assertNotRegexpMatches\",\n    \"assertRegex\",\n    \"assertRegexpMatches\",\n    \"assertSequenceEqual\",\n    \"assertSetEqual\",\n    \"assertTrue\",\n    \"assertTupleEqual\",\n    \"assertWarns\",\n    \"assertWarnsRegex\",\n    \"assert_\",\n    \"failIf\",\n    \"failIfAlmostEqual\",\n    \"failIfEqual\",\n    \"failUnless\",\n    \"failUnlessAlmostEqual\",\n    \"failUnlessEqual\",\n    # below is from Django's SimpleTestCase, leaked here when porting flake8-pytest\n    # TODO(m_burst) disallow Django's SimpleTestCase/TransactionTestCase assertions\n    #  where feasible (#220)\n    \"assertNotContains\",\n)\n\n_UNITTEST_ASSERT_RAISES_NAMES = (\n    # taken from dir(unittest.TestCase) under Python 3.11\n    \"assertRaises\",\n    \"assertRaisesRegex\",\n    \"assertRaisesRegexp\",\n    \"failUnlessRaises\",\n    # below is from Django's SimpleTestCase, leaked here when porting flake8-pytest\n    \"assertRaisesMessage\",\n)\n\n\nclass UnittestAssertionVisitor(Visitor[Config]):\n    def visit_Call(self, node: ast.Call) -> None:\n        if isinstance(node.func, ast.Attribute):\n            if node.func.attr in _UNITTEST_ASSERT_NAMES:\n                self.error_from_node(UnittestAssertion, node, assertion=node.func.attr)\n            elif node.func.attr in _UNITTEST_ASSERT_RAISES_NAMES:\n                self.error_from_node(\n                    UnittestRaisesAssertion, node, assertion=node.func.attr\n                )\n\n\nclass AssertionVisitor(Visitor[Config]):\n    def _is_composite_condition(self, expr: ast.AST) -> bool:\n        # e.g. `a and b`\n        if isinstance(expr, ast.BoolOp) and isinstance(expr.op, ast.And):\n            return True\n\n        # e.g. `not (a or b)`\n        if (\n            isinstance(expr, ast.UnaryOp)\n            and isinstance(expr.op, ast.Not)\n            and isinstance(expr.operand, ast.BoolOp)\n            and isinstance(expr.operand.op, ast.Or)\n        ):\n            return True\n\n        return False\n\n    def visit_Assert(self, node: ast.Assert) -> None:\n        if self._is_composite_condition(node.test):\n            self.error_from_node(CompositeAssertion, node)\n"
  },
  {
    "path": "flake8_pytest_style/visitors/fail.py",
    "content": "import ast\n\nfrom flake8_plugin_utils import Visitor\n\nfrom flake8_pytest_style.config import Config\nfrom flake8_pytest_style.errors import AssertAlwaysFalse, FailWithoutMessage\nfrom flake8_pytest_style.utils import (\n    get_simple_call_args,\n    is_empty_string,\n    is_fail_call,\n    is_falsy_constant,\n)\n\n\nclass FailVisitor(Visitor[Config]):\n    def _check_fail_call(self, node: ast.Call) -> None:\n        \"\"\"Checks for PT016.\"\"\"\n        args = get_simple_call_args(node)\n        # Since pytest 7.0 the argument is named 'reason', and 'msg' is deprecated but\n        # supported (at the time of writing this code).  We check 'reason', then first\n        # positional argument, and then 'msg'.  The edge cases like\n        # `pytest.fail('foo', msg='bar')` and `pytest.fail(reason='foo', msg='bar')`\n        # are deliberately ignored.\n        message_argument = args.get_argument(\"reason\", 0) or args.get_argument(\"msg\")\n        if not message_argument or is_empty_string(message_argument):\n            self.error_from_node(FailWithoutMessage, node)\n\n    def visit_Assert(self, node: ast.Assert) -> None:\n        \"\"\"Checks for PT015.\"\"\"\n        if is_falsy_constant(node.test):\n            self.error_from_node(AssertAlwaysFalse, node)\n\n    def visit_Call(self, node: ast.Call) -> None:\n        if is_fail_call(node):\n            self._check_fail_call(node)\n"
  },
  {
    "path": "flake8_pytest_style/visitors/fixtures.py",
    "content": "import ast\nfrom typing import Set, Type, Union\n\nfrom flake8_plugin_utils import Error, Visitor\n\nfrom flake8_pytest_style.config import Config\nfrom flake8_pytest_style.errors import (\n    DeprecatedYieldFixture,\n    ErroneousUseFixturesOnFixture,\n    ExtraneousScopeFunction,\n    FixtureFinalizerCallback,\n    FixturePositionalArgs,\n    IncorrectFixtureNameUnderscore,\n    IncorrectFixtureParenthesesStyle,\n    MissingFixtureNameUnderscore,\n    UnnecessaryAsyncioMarkOnFixture,\n    UselessYieldFixture,\n)\nfrom flake8_pytest_style.utils import (\n    AnyFunctionDef,\n    get_all_argument_names,\n    get_fixture_decorator,\n    get_mark_decorators,\n    get_mark_name,\n    get_qualname,\n    is_abstract_method,\n    is_pytest_yield_fixture,\n    walk_without_nested_functions,\n)\n\n\nclass FixturesVisitor(Visitor[Config]):\n    def _check_fixture_decorator_name(\n        self, fixture_decorator: Union[ast.Call, ast.Attribute]\n    ) -> None:\n        \"\"\"Checks for PT020.\"\"\"\n        if isinstance(fixture_decorator, ast.Call):\n            is_yield = is_pytest_yield_fixture(fixture_decorator.func)\n        else:\n            is_yield = is_pytest_yield_fixture(fixture_decorator)\n        if is_yield:\n            self.error_from_node(DeprecatedYieldFixture, fixture_decorator)\n\n    def _check_fixture_decorator(\n        self,\n        fixture_decorator: Union[ast.Call, ast.Attribute],\n        fixture_func: AnyFunctionDef,\n    ) -> None:\n        \"\"\"Checks for PT001, PT002, PT003.\"\"\"\n        if not isinstance(fixture_decorator, ast.Call):\n            if self.config.fixture_parentheses:\n                self.error_from_node(\n                    IncorrectFixtureParenthesesStyle,\n                    fixture_decorator,\n                    expected_parens=\"()\",\n                    actual_parens=\"\",\n                )\n            return\n\n        if (\n            not self.config.fixture_parentheses\n            and not fixture_decorator.args\n            and not fixture_decorator.keywords\n        ):\n            self.error_from_node(\n                IncorrectFixtureParenthesesStyle,\n                fixture_decorator,\n                expected_parens=\"\",\n                actual_parens=\"()\",\n            )\n\n        if fixture_decorator.args:\n            self.error_from_node(\n                FixturePositionalArgs, fixture_decorator, name=fixture_func.name\n            )\n\n        for keyword in fixture_decorator.keywords:\n            if (\n                keyword.arg == \"scope\"\n                and isinstance(keyword.value, ast.Constant)\n                and keyword.value.value == \"function\"\n            ):\n                self.error_from_node(\n                    ExtraneousScopeFunction, fixture_decorator, name=fixture_func.name\n                )\n\n    def _check_fixture_returns(self, node: AnyFunctionDef) -> None:\n        \"\"\"Checks for PT004, PT005, PT022.\"\"\"\n        # skip these checks for abstract fixtures\n        if is_abstract_method(node):\n            return\n\n        has_return_with_value = False\n        has_yield_from = False\n        yield_statements = []\n        for child in walk_without_nested_functions(node):\n            if isinstance(child, ast.Yield):\n                yield_statements.append(child)\n            if isinstance(child, (ast.Return, ast.Yield)) and child.value is not None:\n                has_return_with_value = True\n            if isinstance(child, ast.YieldFrom):\n                has_yield_from = True\n\n        if has_return_with_value and node.name.startswith(\"_\"):\n            self.error_from_node(IncorrectFixtureNameUnderscore, node, name=node.name)\n        elif (\n            not has_return_with_value\n            and not has_yield_from\n            and not node.name.startswith(\"_\")\n        ):\n            # we shouldn't fire PT004 if we found a `yield from` because\n            # there is no adequate way to determine whether a value is actually yielded\n            self.error_from_node(MissingFixtureNameUnderscore, node, name=node.name)\n\n        last_statement_is_yield = isinstance(node.body[-1], ast.Expr) and isinstance(\n            node.body[-1].value, ast.Yield\n        )\n        if last_statement_is_yield and len(yield_statements) == 1:\n            self.error_from_node(UselessYieldFixture, node, name=node.name)\n\n    def _check_fixture_addfinalizer(self, node: AnyFunctionDef) -> None:\n        \"\"\"Checks for PT021.\"\"\"\n        if \"request\" not in get_all_argument_names(node.args):\n            return\n\n        for child in walk_without_nested_functions(node):  # pragma: no branch\n            if (\n                isinstance(child, ast.Call)\n                and get_qualname(child.func) == \"request.addfinalizer\"\n            ):\n                self.error_from_node(FixtureFinalizerCallback, child)\n                return\n\n    def _check_fixture_marks(self, node: AnyFunctionDef) -> None:\n        \"\"\"Checks for PT024, PT025.\"\"\"\n        reported_errors: Set[Type[Error]] = set()\n        marks = get_mark_decorators(node)\n        for mark in marks:\n            mark_name = get_mark_name(mark)\n            if (\n                mark_name == \"asyncio\"\n                and UnnecessaryAsyncioMarkOnFixture not in reported_errors\n            ):\n                self.error_from_node(UnnecessaryAsyncioMarkOnFixture, mark)\n                reported_errors.add(UnnecessaryAsyncioMarkOnFixture)\n            if (\n                mark_name == \"usefixtures\"\n                and ErroneousUseFixturesOnFixture not in reported_errors\n            ):\n                self.error_from_node(ErroneousUseFixturesOnFixture, mark)\n                reported_errors.add(ErroneousUseFixturesOnFixture)\n\n    def visit_FunctionDef(self, node: AnyFunctionDef) -> None:\n        fixture_decorator = get_fixture_decorator(node)\n        if fixture_decorator:\n            self._check_fixture_decorator_name(fixture_decorator)\n            self._check_fixture_decorator(fixture_decorator, node)\n            self._check_fixture_returns(node)\n            self._check_fixture_addfinalizer(node)\n            self._check_fixture_marks(node)\n\n        self.generic_visit(node)\n\n    visit_AsyncFunctionDef = visit_FunctionDef  # noqa: N815\n"
  },
  {
    "path": "flake8_pytest_style/visitors/imports.py",
    "content": "import ast\n\nfrom flake8_plugin_utils import Visitor\n\nfrom flake8_pytest_style.config import Config\nfrom flake8_pytest_style.errors import IncorrectPytestImport\n\n\ndef _is_pytest_or_subpackage(imported_name: str) -> bool:\n    return imported_name == \"pytest\" or imported_name.startswith(\"pytest.\")\n\n\nclass ImportsVisitor(Visitor[Config]):\n    def visit_Import(self, node: ast.Import) -> None:\n        for name in node.names:\n            if (\n                _is_pytest_or_subpackage(name.name)\n                and name.asname\n                and name.asname != name.name\n            ):\n                self.error_from_node(IncorrectPytestImport, node)\n\n    def visit_ImportFrom(self, node: ast.ImportFrom) -> None:\n        if node.level != 0 or node.module is None:  # relative import\n            return\n        if _is_pytest_or_subpackage(node.module):\n            self.error_from_node(IncorrectPytestImport, node)\n"
  },
  {
    "path": "flake8_pytest_style/visitors/marks.py",
    "content": "import ast\nfrom typing import Union\n\nfrom flake8_plugin_utils import Visitor\n\nfrom flake8_pytest_style.config import Config\nfrom flake8_pytest_style.errors import (\n    IncorrectMarkParenthesesStyle,\n    UseFixturesWithoutParameters,\n)\nfrom flake8_pytest_style.utils import (\n    AnyDecoratorTarget,\n    get_mark_decorators,\n    get_mark_name,\n)\n\n\nclass MarksVisitor(Visitor[Config]):\n    def _check_mark_parentheses(\n        self, mark_decorator: Union[ast.Call, ast.Attribute]\n    ) -> None:\n        \"\"\"Checks for PT023.\"\"\"\n\n        if not isinstance(mark_decorator, ast.Call):\n            if self.config.mark_parentheses:\n                self.error_from_node(\n                    IncorrectMarkParenthesesStyle,\n                    mark_decorator,\n                    mark_name=get_mark_name(mark_decorator),\n                    expected_parens=\"()\",\n                    actual_parens=\"\",\n                )\n            return\n\n        if (\n            not self.config.mark_parentheses\n            and not mark_decorator.args\n            and not mark_decorator.keywords\n        ):\n            self.error_from_node(\n                IncorrectMarkParenthesesStyle,\n                mark_decorator,\n                mark_name=get_mark_name(mark_decorator.func),\n                expected_parens=\"\",\n                actual_parens=\"()\",\n            )\n\n    def _check_useless_usefixtures(\n        self, mark_decorator: Union[ast.Call, ast.Attribute]\n    ) -> None:\n        \"\"\"Checks for PT026.\"\"\"\n\n        if get_mark_name(mark_decorator) != \"usefixtures\":\n            return\n\n        has_parameters = isinstance(mark_decorator, ast.Call) and bool(\n            mark_decorator.args or mark_decorator.keywords\n        )\n        if not has_parameters:\n            self.error_from_node(UseFixturesWithoutParameters, mark_decorator)\n\n    def visit_FunctionDef(self, node: AnyDecoratorTarget) -> None:\n        mark_decorators = get_mark_decorators(node)\n        for mark_decorator in mark_decorators:\n            self._check_mark_parentheses(mark_decorator)\n            self._check_useless_usefixtures(mark_decorator)\n\n    visit_AsyncFunctionDef = visit_FunctionDef  # noqa: N815\n\n    def visit_ClassDef(self, node: ast.ClassDef) -> None:\n        self.visit_FunctionDef(node)\n\n        # recurse into classes\n        self.generic_visit(node)\n"
  },
  {
    "path": "flake8_pytest_style/visitors/parametrize.py",
    "content": "import ast\nimport itertools\nfrom typing import Optional\n\nfrom flake8_plugin_utils import Visitor, check_equivalent_nodes\n\nfrom ..config import (\n    Config,\n    ParametrizeNamesType,\n    ParametrizeValuesRowType,\n    ParametrizeValuesType,\n)\nfrom ..errors import (\n    DuplicateParametrizeTestCases,\n    ParametrizeNamesWrongType,\n    ParametrizeValuesWrongType,\n)\nfrom ..utils import extract_parametrize_call_args, is_parametrize_call\n\n\nclass ParametrizeVisitor(Visitor[Config]):\n    def _check_parametrize_names(\n        self, node: ast.Call, names: ast.AST\n    ) -> Optional[bool]:\n        \"\"\"\n        Handles names in parametrize, checks for PT006.\n\n        Returns a flag indicating whether parametrize has multiple names,\n        or None if we can't tell.\n        \"\"\"\n\n        multiple_names: Optional[bool] = None\n        found_type: Optional[ParametrizeNamesType] = None\n        if isinstance(names, ast.Constant) and isinstance(names.value, str):\n            if \",\" in names.value:\n                found_type = ParametrizeNamesType.CSV\n                multiple_names = True\n            else:\n                multiple_names = False\n        elif isinstance(names, (ast.List, ast.Tuple)):\n            multiple_names = len(names.elts) > 1\n            if not multiple_names:\n                self.error_from_node(\n                    ParametrizeNamesWrongType, node, expected_type=\"string\"\n                )\n            elif isinstance(names, ast.Tuple):\n                found_type = ParametrizeNamesType.TUPLE\n            else:\n                found_type = ParametrizeNamesType.LIST\n        if multiple_names and found_type != self.config.parametrize_names_type:\n            self.error_from_node(\n                ParametrizeNamesWrongType,\n                node,\n                expected_type=self.config.parametrize_names_type.value,\n            )\n        return multiple_names\n\n    def _get_expected_values_type_str(self, multiple_names: Optional[bool]) -> str:\n        if multiple_names:\n            return (\n                f\"{self.config.parametrize_values_type.value}\"\n                f\" of {self.config.parametrize_values_row_type.value}s\"\n            )\n        return self.config.parametrize_values_type.value\n\n    def _check_parametrize_values(\n        self, node: ast.Call, values: Optional[ast.AST], multiple_names: Optional[bool]\n    ) -> None:\n        \"\"\"Checks for PT007.\"\"\"\n        expected_type_str = self._get_expected_values_type_str(multiple_names)\n\n        if isinstance(values, ast.List):\n            top_level_type = ParametrizeValuesType.LIST\n        elif isinstance(values, ast.Tuple):\n            top_level_type = ParametrizeValuesType.TUPLE\n        else:\n            return\n\n        if top_level_type != self.config.parametrize_values_type:\n            self.error_from_node(\n                ParametrizeValuesWrongType, node, expected_type=expected_type_str\n            )\n            return\n\n        if multiple_names:\n            for element in values.elts:\n                found_row_type: Optional[ParametrizeValuesRowType] = None\n                if isinstance(element, ast.List):\n                    found_row_type = ParametrizeValuesRowType.LIST\n                elif isinstance(element, ast.Tuple):\n                    found_row_type = ParametrizeValuesRowType.TUPLE\n                if (\n                    found_row_type\n                    and found_row_type != self.config.parametrize_values_row_type\n                ):\n                    self.error_from_node(\n                        ParametrizeValuesWrongType,\n                        node,\n                        expected_type=expected_type_str,\n                    )\n                    break\n\n    def _check_parametrize_duplicates(\n        self, node: ast.AST, values: Optional[ast.AST]\n    ) -> None:\n        \"\"\"Checks for PT014.\"\"\"\n        if not isinstance(values, (ast.List, ast.Tuple, ast.Set)):\n            return\n\n        for (i, element1), (j, element2) in itertools.combinations(\n            enumerate(values.elts, start=1), 2\n        ):\n            if check_equivalent_nodes(element1, element2):\n                self.error_from_node(\n                    DuplicateParametrizeTestCases, node, indexes=(i, j)\n                )\n\n    def _check_parametrize_call(self, node: ast.Call) -> None:\n        \"\"\"Checks for all violations regarding `pytest.mark.parametrize` calls.\"\"\"\n        args = extract_parametrize_call_args(node)\n        if not args:\n            return\n\n        multiple_names = self._check_parametrize_names(node, args.names)\n\n        self._check_parametrize_values(node, args.values, multiple_names)\n\n        self._check_parametrize_duplicates(node, args.values)\n\n    def visit_Call(self, node: ast.Call) -> None:\n        if is_parametrize_call(node):\n            self._check_parametrize_call(node)\n"
  },
  {
    "path": "flake8_pytest_style/visitors/patch.py",
    "content": "import ast\n\nfrom flake8_plugin_utils import Visitor\n\nfrom flake8_pytest_style.config import Config\nfrom flake8_pytest_style.errors import PatchWithLambda\nfrom flake8_pytest_style.utils import (\n    get_all_argument_names,\n    get_qualname,\n    get_simple_call_args,\n)\n\n_PATCH_NAMESPACES = (\n    \"mocker\",\n    \"class_mocker\",\n    \"module_mocker\",\n    \"package_mocker\",\n    \"session_mocker\",\n    \"mock\",\n    \"unittest.mock\",\n)\n_PATCH_NAMES = (\"patch\",) + tuple(\n    f\"{namespace}.patch\" for namespace in _PATCH_NAMESPACES\n)\n_PATCH_OBJECT_NAMES = tuple(f\"{name}.object\" for name in _PATCH_NAMES)\n\n\nclass PatchVisitor(Visitor[Config]):\n    def _check_patch_call(self, node: ast.Call, new_arg_number: int) -> None:\n        \"\"\"\n        Checks for PT008.\n\n        :param node: patch call node\n        :param new_arg_number: number of `new` positional argument of patch func\n        \"\"\"\n        args = get_simple_call_args(node)\n        if args.get_argument(\"return_value\") is not None:\n            return\n\n        new_arg = args.get_argument(\"new\", new_arg_number)\n        if not isinstance(new_arg, ast.Lambda):\n            return\n\n        lambda_argnames = set(get_all_argument_names(new_arg.args))\n\n        for child_node in ast.walk(new_arg.body):\n            if isinstance(child_node, ast.Name) and child_node.id in lambda_argnames:\n                break\n        else:\n            self.error_from_node(PatchWithLambda, node)\n\n    def visit_Call(self, node: ast.Call) -> None:\n        if get_qualname(node.func) in _PATCH_NAMES:\n            # attributes are (target, new, ...)\n            self._check_patch_call(node, 1)\n\n        if get_qualname(node.func) in _PATCH_OBJECT_NAMES:\n            # attributes are (target, attribute, new, ...)\n            self._check_patch_call(node, 2)\n"
  },
  {
    "path": "flake8_pytest_style/visitors/raises.py",
    "content": "import ast\n\nfrom flake8_plugin_utils import Visitor\n\nfrom flake8_pytest_style.config import Config\nfrom flake8_pytest_style.errors import (\n    RaisesTooBroad,\n    RaisesWithMultipleStatements,\n    RaisesWithoutException,\n)\nfrom flake8_pytest_style.utils import (\n    get_qualname,\n    get_simple_call_args,\n    is_empty_string,\n    is_none,\n    is_nontrivial_with_statement,\n    is_raises_call,\n    is_raises_with,\n)\n\n\nclass RaisesVisitor(Visitor[Config]):\n    def _check_raises_call(self, node: ast.Call) -> None:\n        \"\"\"\n        Checks for violations regarding `pytest.raises` call args (PT010 and PT011).\n        \"\"\"\n        args = get_simple_call_args(node)\n        exception = args.get_argument(\"expected_exception\", position=0)\n        if not exception:\n            self.error_from_node(RaisesWithoutException, node)\n            return\n\n        exception_name = get_qualname(exception)\n        if exception_name not in self.config.raises_require_match_for:\n            return\n        match = args.get_argument(\"match\")\n        if match is None or is_none(match) or is_empty_string(match):\n            self.error_from_node(RaisesTooBroad, node, exception=exception_name)\n\n    def _check_raises_with(self, node: ast.With) -> None:\n        \"\"\"Checks for PT012.\"\"\"\n        body = node.body\n\n        is_complex_body = False\n        if len(body) != 1:\n            is_complex_body = True\n        elif isinstance(\n            body[0],\n            (\n                ast.If,\n                ast.For,\n                ast.AsyncFor,\n                ast.While,\n                ast.Try,\n            ),\n        ):\n            is_complex_body = True\n        elif is_nontrivial_with_statement(body[0]):\n            is_complex_body = True\n\n        if is_complex_body:\n            self.error_from_node(RaisesWithMultipleStatements, node)\n\n    def visit_Call(self, node: ast.Call) -> None:\n        if is_raises_call(node):\n            self._check_raises_call(node)\n\n    def visit_With(self, node: ast.With) -> None:\n        if is_raises_with(node):\n            self._check_raises_with(node)\n\n        self.generic_visit(node)\n"
  },
  {
    "path": "flake8_pytest_style/visitors/t_functions.py",
    "content": "from flake8_plugin_utils import Visitor\n\nfrom flake8_pytest_style.config import Config\nfrom flake8_pytest_style.errors import (\n    FixtureParamWithoutValue,\n    TFunctionArgumentWithDefault,\n)\nfrom flake8_pytest_style.utils import AnyFunctionDef, is_test_function\n\n\n# This should be named `TestFunctionsVisitor` (and the module `test_functions`),\n# but this way it is easier to avoid confusion with the `Test` prefix in pytest.\nclass TFunctionsVisitor(Visitor[Config]):\n    def _check_test_function_args(self, node: AnyFunctionDef) -> None:\n        \"\"\"Checks for PT019, P028.\"\"\"\n        # intentionally not looking at posonlyargs because pytest passes everything\n        # as kwargs, so declaring fixture args as positional-only will fail anyway\n        for arg in node.args.args + node.args.kwonlyargs:\n            if arg.arg.startswith(\"_\"):\n                # The error is raised at the position of `node` (function call),\n                # not `arg`, to preserve backwards compatibility.\n                self.error_from_node(FixtureParamWithoutValue, node, name=arg.arg)\n\n        if node.args.defaults:\n            pos_args = node.args.posonlyargs + node.args.args\n            pos_args_with_defaults = pos_args[-len(node.args.defaults) :]  # noqa: E203\n            for arg in pos_args_with_defaults:\n                self.error_from_node(\n                    TFunctionArgumentWithDefault, arg, name=node.name, arg=arg.arg\n                )\n\n        for arg, default in zip(node.args.kwonlyargs, node.args.kw_defaults):\n            if default is not None:\n                self.error_from_node(\n                    TFunctionArgumentWithDefault, arg, name=node.name, arg=arg.arg\n                )\n\n    def visit_FunctionDef(self, node: AnyFunctionDef) -> None:\n        if is_test_function(node):\n            self._check_test_function_args(node)\n\n        self.generic_visit(node)\n\n    visit_AsyncFunctionDef = visit_FunctionDef  # noqa: N815\n"
  },
  {
    "path": "flake8_pytest_style/visitors/try_except.py",
    "content": "import ast\nfrom typing import List, Optional\n\nfrom flake8_plugin_utils import Visitor\n\nfrom flake8_pytest_style.config import Config\nfrom flake8_pytest_style.errors import AssertInExcept\n\n\nclass TryExceptVisitor(Visitor[Config]):\n    def __init__(self, config: Optional[Config] = None) -> None:\n        super().__init__(config=config)\n        self._exception_names: List[str] = []\n        self._current_assert: Optional[ast.Assert] = None\n\n    def visit_ExceptHandler(self, node: ast.ExceptHandler) -> None:\n        if node.name:\n            self._exception_names.append(node.name)\n        try:\n            self.generic_visit(node)\n        finally:\n            if node.name:\n                self._exception_names.pop()\n\n    def visit_Assert(self, node: ast.Assert) -> None:\n        self._current_assert = node\n        try:\n            self.visit(node.test)\n        finally:\n            self._current_assert = None\n\n        if node.msg:\n            self.visit(node.msg)\n\n    def visit_Name(self, node: ast.Name) -> None:\n        if self._current_assert:\n            if node.id in self._exception_names:\n                self.error_from_node(AssertInExcept, self._current_assert, name=node.id)\n"
  },
  {
    "path": "flake8_pytest_style/visitors/warns.py",
    "content": "import ast\n\nfrom flake8_plugin_utils import Visitor\n\nfrom flake8_pytest_style.config import Config\nfrom flake8_pytest_style.errors import (\n    WarnsTooBroad,\n    WarnsWithMultipleStatements,\n    WarnsWithoutException,\n)\nfrom flake8_pytest_style.utils import (\n    get_qualname,\n    get_simple_call_args,\n    is_empty_string,\n    is_none,\n    is_nontrivial_with_statement,\n    is_warns_call,\n    is_warns_with,\n)\n\n\nclass WarnsVisitor(Visitor[Config]):\n    def _check_warns_call(self, node: ast.Call) -> None:\n        \"\"\"\n        Checks for violations regarding `pytest.warns` call args (PT029 and PT030).\n        \"\"\"\n        args = get_simple_call_args(node)\n        warning = args.get_argument(\"expected_warning\", position=0)\n        if not warning:\n            self.error_from_node(WarnsWithoutException, node)\n            return\n\n        warning_name = get_qualname(warning)\n        if warning_name not in self.config.warns_require_match_for:\n            return\n        match = args.get_argument(\"match\")\n        if match is None or is_none(match) or is_empty_string(match):\n            self.error_from_node(WarnsTooBroad, node, warning=warning_name)\n\n    def _check_warns_with(self, node: ast.With) -> None:\n        \"\"\"Checks for PT031.\"\"\"\n        body = node.body\n\n        is_complex_body = False\n        if len(body) != 1:\n            is_complex_body = True\n        elif isinstance(\n            body[0],\n            (\n                ast.If,\n                ast.For,\n                ast.AsyncFor,\n                ast.While,\n                ast.Try,\n            ),\n        ):\n            is_complex_body = True\n        elif is_nontrivial_with_statement(body[0]):\n            is_complex_body = True\n\n        if is_complex_body:\n            self.error_from_node(WarnsWithMultipleStatements, node)\n\n    def visit_Call(self, node: ast.Call) -> None:\n        if is_warns_call(node):\n            self._check_warns_call(node)\n\n    def visit_With(self, node: ast.With) -> None:\n        if is_warns_with(node):\n            self._check_warns_with(node)\n\n        self.generic_visit(node)\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[project]\nname = \"flake8-pytest-style\"\nversion = \"2.2.0\"\ndescription = \"A flake8 plugin checking common style issues or inconsistencies with pytest-based tests.\"\nauthors = [\n  { name = \"Mikhail Burshteyn\", email = \"mdburshteyn@gmail.com\" },\n]\nlicense = \"MIT\"\nreadme = 'README.md'\nkeywords = [\"flake8\", \"pytest\"]\ndynamic = [\n  \"classifiers\",\n  \"dependencies\",\n]\nrequires-python = \">=3.10\"\n\n[project.urls]\nrepository = \"https://github.com/m-burst/flake8-pytest-style\"\nhomepage = \"https://pypi.org/project/flake8-pytest-style\"\n\n[tool.poetry]\nclassifiers = [\n  \"Development Status :: 5 - Production/Stable\",\n  \"Environment :: Console\",\n  \"Environment :: Plugins\",\n  \"Framework :: Flake8\",\n  \"Framework :: Pytest\",\n  \"Intended Audience :: Developers\",\n  \"Operating System :: OS Independent\",\n  \"Topic :: Software Development :: Quality Assurance\",\n  \"Topic :: Software Development :: Testing\",\n  \"Topic :: Software Development :: Testing :: Unit\",\n]\n\n[project.entry-points.\"flake8.extension\"]\nPT = 'flake8_pytest_style.plugin:PytestStylePlugin'\n\n[tool.poetry.dependencies]\npython = \"^3.10\"\nflake8-plugin-utils = \"^1.3.2\"\n\n[tool.poetry.group.dev.dependencies]\nblack = \"^26.3.1\"\nbump2version = \"^1.0.1\"\nmypy = \">=1.20.2\"\npylint = \"^4.0.5\"\npytest = \"^9.0.3\"\npytest-cov = \"^7.1.0\"\npytest-deadfixtures = \"^3.1\"\nflake8 = \"^7.3.0\"\npytest-mock = \"^3.15.1\"\ntomlkit = \">=0.12.1,<0.15.0\"\n\n# The below group is taken from flake8-awesome with some exclusions\n# that are irrelevant or unsupported.\n# TODO remove Python version restriction after Bandit supports 3.14\n# https://github.com/PyCQA/bandit/issues/1314\nflake8-bandit = {version = \"*\", python=\"<3.14\"}\nflake8-breakpoint = \"*\"\nflake8-bugbear = \"*\"\nflake8-builtins = \"*\"\nflake8-comprehensions = \"*\"\nflake8-eradicate = \"*\"\nflake8-if-expr = \"*\"\nflake8-isort = \"*\"\nflake8-print = \"*\"\nflake8-requirements = \"*\"\npep8-naming = \"*\"\n\n# broken on 3.14+\n# flake8-annotations-complexity = \"*\"\n\n# broken on 3.14+\n# flake8-expression-complexity = \"*\"\n\n# kinda broken on 3.12+ (needs pkg_resources), not needed here\n# flake8-logging-format = \"*\"\n\n# functionality implemented in this plugin\n# flake8-pytest = \"*\"\n\n# actually this plugin\n# flake8-pytest-style = \"*\"\n\n# broken on 3.14+, and probably not needed with mypy\n# flake8-return = \"*\"\n\n# end of flake8-awesome\n\n[build-system]\nrequires = [\"poetry-core>=1.0.0\"]\nbuild-backend = \"poetry.core.masonry.api\"\n"
  },
  {
    "path": "scripts/pypi_readme.py",
    "content": "#!/usr/bin/env python3\nimport pathlib\nimport re\nfrom typing import Match, cast\n\nimport tomlkit\nfrom tomlkit.container import Container\n\n\ndef process_readme(readme: str, project_metadata: Container) -> str:\n    urls = cast(Container, project_metadata[\"urls\"])\n    repository = cast(str, urls[\"repository\"])\n    version = cast(str, project_metadata[\"version\"])\n    base_url = f\"{repository}/blob/v{version}/\"\n\n    def replace_url(match: Match[str]) -> str:\n        path_without_leading_slash = match.group(0).lstrip(\"/\")\n        return f\"{base_url}{path_without_leading_slash}\"\n\n    return re.sub(r\"/?\\S+\\.md\", replace_url, readme)\n\n\ndef make_output_filename(input_filename: str) -> str:\n    path = pathlib.Path(input_filename)\n    return str(path.parent / f\"{path.stem}-pypi{path.suffix}\")\n\n\ndef main() -> None:\n    with open(\"pyproject.toml\") as pyproject_file:\n        pyproject_data = tomlkit.loads(pyproject_file.read())\n    project_metadata = cast(Container, pyproject_data[\"project\"])\n\n    readme_filename = cast(str, project_metadata[\"readme\"])\n    with open(readme_filename) as input_file:\n        input_readme = input_file.read()\n\n    output_readme = process_readme(input_readme, project_metadata)\n    output_filename = make_output_filename(readme_filename)\n    with open(output_filename, \"w\") as output_file:\n        output_file.write(output_readme)\n\n    project_metadata[\"readme\"] = output_filename\n    with open(\"pyproject.toml\", \"w\") as pyproject_file:\n        pyproject_file.write(tomlkit.dumps(pyproject_data))\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "setup.cfg",
    "content": "[flake8]\nenable-extensions = G\nexclude = .git, .venv\nextend-ignore =\n    ; 'id' is a python builtin, consider renaming the class attribute\n    A003,\n    ; line break before binary operator\n    W503,\nmax-complexity = 10\nmax-line-length = 88\nper-file-ignores =\n    flake8_pytest_style/visitors/*.py:N802\n    tests/*.py:S101\nshow-source = True\n\n[mypy]\ncheck_untyped_defs = True\ndisallow_any_generics = True\ndisallow_incomplete_defs = True\ndisallow_untyped_defs = True\nignore_missing_imports = True\nno_implicit_optional = True\n\n[mypy-tests.*]\ndisallow_incomplete_defs = False\ndisallow_untyped_defs = False\n\n[isort]\nbalanced_wrapping = True\ndefault_section = THIRDPARTY\ninclude_trailing_comma = True\nknown_first_party = flake8_pytest_style, tests\nline_length = 88\nmulti_line_output = 3\n\n[pylint]\ngood-names = i,j,k,e,x,_,pk,id\nmax-args = 5\nmax-attributes = 10\nmax-bool-expr = 5\nmax-branches = 10\nmax-locals = 8\nmax-module-lines = 500\nmax-nested-blocks = 3\nmax-public-methods = 10\nmax-returns = 5\nmax-statements = 25\noutput-format = colorized\n\ndisable =\n    C0103, ; Constant name \"api\" doesn't conform to UPPER_CASE naming style (invalid-name)\n    C0111, ; Missing module docstring (missing-docstring)\n    E0213, ; Method should have \"self\" as first argument (no-self-argument) - N805 for flake8\n    R0801, ; Similar lines in 2 files (duplicate-code)\n    R0901, ; Too many ancestors (m/n) (too-many-ancestors)\n    R0903, ; Too few public methods (m/n) (too-few-public-methods)\n\nignored-classes =\n    contextlib.closing,\n\n[coverage:run]\nomit = tests/*,**/__main__.py\nbranch = True\n\n[coverage:report]\nshow_missing = True\nskip_covered = True\nfail_under = 90\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/conftest.py",
    "content": ""
  },
  {
    "path": "tests/test_PT001_incorrect_fixture_parentheses_style.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import IncorrectFixtureParenthesesStyle\nfrom flake8_pytest_style.visitors import FixturesVisitor\n\n# make the configs independent of the actual default\n_CONFIG_WITHOUT_PARENS = DEFAULT_CONFIG._replace(fixture_parentheses=False)\n_CONFIG_WITH_PARENS = DEFAULT_CONFIG._replace(fixture_parentheses=True)\n\n\ndef test_ok_no_parameters():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture()\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=_CONFIG_WITH_PARENS)\n\n\ndef test_ok_with_parameters():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture(scope='module')\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=_CONFIG_WITH_PARENS)\n\n\ndef test_ok_without_parens():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=_CONFIG_WITHOUT_PARENS)\n\n\ndef test_error_without_parens():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_error(\n        FixturesVisitor,\n        code,\n        IncorrectFixtureParenthesesStyle,\n        config=_CONFIG_WITH_PARENS,\n        expected_parens=\"()\",\n        actual_parens=\"\",\n    )\n\n\ndef test_error_with_parens():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture()\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_error(\n        FixturesVisitor,\n        code,\n        IncorrectFixtureParenthesesStyle,\n        config=_CONFIG_WITHOUT_PARENS,\n        expected_parens=\"\",\n        actual_parens=\"()\",\n    )\n"
  },
  {
    "path": "tests/test_PT002_fixture_positional_args.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import FixturePositionalArgs\nfrom flake8_pytest_style.visitors import FixturesVisitor\n\n\ndef test_ok_no_args():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_only_kwargs():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture(scope='module')\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_error_only_args():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture('module')\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_error(\n        FixturesVisitor,\n        code,\n        FixturePositionalArgs,\n        name=\"my_fixture\",\n        config=DEFAULT_CONFIG,\n    )\n\n\ndef test_error_mixed():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture('module', autouse=True)\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_error(\n        FixturesVisitor,\n        code,\n        FixturePositionalArgs,\n        name=\"my_fixture\",\n        config=DEFAULT_CONFIG,\n    )\n"
  },
  {
    "path": "tests/test_PT003_extraneous_scope_function.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import ExtraneousScopeFunction\nfrom flake8_pytest_style.visitors import FixturesVisitor\n\n\ndef test_ok_no_scope():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_other_scope():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture(scope='module')\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_error():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture(scope='function')\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_error(FixturesVisitor, code, ExtraneousScopeFunction, config=DEFAULT_CONFIG)\n"
  },
  {
    "path": "tests/test_PT004_missing_fixture_name_underscore.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import MissingFixtureNameUnderscore\nfrom flake8_pytest_style.visitors import FixturesVisitor\n\n\ndef test_ok_simple():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def _patch_something(mocker):\n            mocker.patch('some.thing')\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_with_return():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def _patch_something(mocker):\n            if something:\n                return\n            mocker.patch('some.thing')\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_with_yield():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def _activate_context():\n            with context:\n                yield\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_abstract_with_import_abc():\n    code = \"\"\"\n        import abc\n\n        import pytest\n\n        class BaseTest:\n            @pytest.fixture\n            @abc.abstractmethod\n            def my_fixture():\n                raise NotImplementedError\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_abstract_with_from_import():\n    code = \"\"\"\n        from abc import abstractmethod\n\n        import pytest\n\n        class BaseTest:\n            @pytest.fixture\n            @abstractmethod\n            def my_fixture():\n                raise NotImplementedError\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_ignoring_yield_from():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture():\n            yield from some_generator()\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_error_simple():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def patch_something(mocker):\n            mocker.patch('some.thing')\n    \"\"\"\n    assert_error(\n        FixturesVisitor,\n        code,\n        MissingFixtureNameUnderscore,\n        name=\"patch_something\",\n        config=DEFAULT_CONFIG,\n    )\n\n\ndef test_error_with_yield():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def activate_context():\n            with context:\n                yield\n    \"\"\"\n    assert_error(\n        FixturesVisitor,\n        code,\n        MissingFixtureNameUnderscore,\n        name=\"activate_context\",\n        config=DEFAULT_CONFIG,\n    )\n"
  },
  {
    "path": "tests/test_PT005_incorrect_fixture_name_underscore.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import IncorrectFixtureNameUnderscore\nfrom flake8_pytest_style.visitors import FixturesVisitor\n\n\ndef test_ok_with_return():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture(mocker):\n            return 0\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_with_yield():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def activate_context():\n            with get_context() as context:\n                yield context\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_nested_function():\n    code = \"\"\"\n        @pytest.fixture\n        def _any_fixture(mocker):\n            def nested_function():\n                return 1\n\n            mocker.patch('...', nested_function)\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_abstract_with_import_abc():\n    code = \"\"\"\n        import abc\n\n        import pytest\n\n        class BaseTest:\n            @pytest.fixture\n            @abc.abstractmethod\n            def _my_fixture():\n                return NotImplemented\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_abstract_with_from_import():\n    code = \"\"\"\n        from abc import abstractmethod\n\n        import pytest\n\n        class BaseTest:\n            @pytest.fixture\n            @abstractmethod\n            def _my_fixture():\n                return NotImplemented\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_error_with_return():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def _my_fixture(mocker):\n            return 0\n    \"\"\"\n    assert_error(\n        FixturesVisitor,\n        code,\n        IncorrectFixtureNameUnderscore,\n        name=\"_my_fixture\",\n        config=DEFAULT_CONFIG,\n    )\n\n\ndef test_error_with_yield():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def _activate_context():\n            with get_context() as context:\n                yield context\n    \"\"\"\n    assert_error(\n        FixturesVisitor,\n        code,\n        IncorrectFixtureNameUnderscore,\n        name=\"_activate_context\",\n        config=DEFAULT_CONFIG,\n    )\n\n\ndef test_error_with_conditional_yield_from():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def _activate_context():\n            if some_condition:\n                with get_context() as context:\n                    yield context\n            else:\n                yield from other_context()\n    \"\"\"\n    # since we have yield with value in one branch,\n    # we assume that the fixture yields a value\n    assert_error(\n        FixturesVisitor,\n        code,\n        IncorrectFixtureNameUnderscore,\n        name=\"_activate_context\",\n        config=DEFAULT_CONFIG,\n    )\n"
  },
  {
    "path": "tests/test_PT006_parametrize_names_wrong_type.py",
    "content": "import pytest\nfrom flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG, ParametrizeNamesType\nfrom flake8_pytest_style.errors import ParametrizeNamesWrongType\nfrom flake8_pytest_style.visitors import ParametrizeVisitor\n\nNAMES_CSV = \"name1,name2\"\nNAMES_LIST = [\"name1\", \"name2\"]\nNAMES_TUPLE = (\"name1\", \"name2\")\n\n\ndef test_ok_single():\n    code = \"\"\"\n        import pytest\n\n        pytest.mark.parametrize(\n            'name',\n            ['a', 'b', 'c'],\n        )\n    \"\"\"\n    assert_not_error(ParametrizeVisitor, code, config=DEFAULT_CONFIG)\n\n\n@pytest.mark.parametrize(\n    (\"cfg_type\", \"names\"),\n    [\n        (ParametrizeNamesType.CSV, NAMES_CSV),\n        (ParametrizeNamesType.LIST, NAMES_LIST),\n        (ParametrizeNamesType.TUPLE, NAMES_TUPLE),\n    ],\n)\ndef test_ok_multiple(cfg_type, names):\n    code = f\"\"\"\n        import pytest\n\n        pytest.mark.parametrize(\n            {names!r},\n            [\n                ('a', 'b'),\n                ('c', 'd'),\n            ],\n        )\n    \"\"\"\n    config = DEFAULT_CONFIG._replace(parametrize_names_type=cfg_type)\n    assert_not_error(ParametrizeVisitor, code, config=config)\n\n\ndef test_error_single_tuple():\n    code = \"\"\"\n        import pytest\n\n        pytest.mark.parametrize(\n            ('name',),\n            ['a', 'b', 'c'],\n        )\n    \"\"\"\n    assert_error(\n        ParametrizeVisitor,\n        code,\n        ParametrizeNamesWrongType,\n        expected_type=\"string\",\n        config=DEFAULT_CONFIG,\n    )\n\n\n@pytest.mark.parametrize(\n    (\"cfg_type\", \"names\"),\n    [\n        (ParametrizeNamesType.CSV, NAMES_LIST),\n        (ParametrizeNamesType.CSV, NAMES_TUPLE),\n        (ParametrizeNamesType.LIST, NAMES_CSV),\n        (ParametrizeNamesType.LIST, NAMES_TUPLE),\n        (ParametrizeNamesType.TUPLE, NAMES_CSV),\n        (ParametrizeNamesType.TUPLE, NAMES_LIST),\n    ],\n)\ndef test_error_multiple(cfg_type, names):\n    code = f\"\"\"\n        import pytest\n\n        pytest.mark.parametrize(\n            {names!r},\n            [\n                ('a', 'b'),\n                ('c', 'd'),\n            ],\n        )\n    \"\"\"\n    config = DEFAULT_CONFIG._replace(parametrize_names_type=cfg_type)\n    assert_error(\n        ParametrizeVisitor,\n        code,\n        ParametrizeNamesWrongType,\n        expected_type=cfg_type.value,\n        config=config,\n    )\n"
  },
  {
    "path": "tests/test_PT007_parametrize_values_wrong_type.py",
    "content": "import pytest\nfrom flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import (\n    DEFAULT_CONFIG,\n    ParametrizeValuesRowType,\n    ParametrizeValuesType,\n)\nfrom flake8_pytest_style.errors import ParametrizeValuesWrongType\nfrom flake8_pytest_style.visitors import ParametrizeVisitor\n\nVALUES_LIST = [\"a\", \"b\", \"c\"]\nVALUES_TUPLE = (\"a\", \"b\", \"c\")\nVALUES_LIST_OF_LISTS = [[\"a\", \"b\"], [\"c\", \"d\"]]\nVALUES_LIST_OF_TUPLES = [(\"a\", \"b\"), (\"c\", \"d\")]\nVALUES_TUPLE_OF_LISTS = ([\"a\", \"b\"], [\"c\", \"d\"])\nVALUES_TUPLE_OF_TUPLES = ((\"a\", \"b\"), (\"c\", \"d\"))\nVALUES_LIST_OF_MIXED = [[\"a\", \"b\"], (\"c\", \"d\")]\nVALUES_TUPLE_OF_MIXED = ([\"a\", \"b\"], (\"c\", \"d\"))\n\n\ndef _get_expected_type_str(values_cfg_type, rows_cfg_type):\n    return f\"{values_cfg_type.value} of {rows_cfg_type.value}s\"\n\n\n@pytest.mark.parametrize(\n    (\"values_cfg_type\", \"values\"),\n    [\n        (ParametrizeValuesType.LIST, VALUES_LIST),\n        (ParametrizeValuesType.TUPLE, VALUES_TUPLE),\n    ],\n)\ndef test_ok_single(values_cfg_type, values):\n    code = f\"\"\"\n        import pytest\n\n        pytest.mark.parametrize(\n            'name',\n            {values!r},\n        )\n    \"\"\"\n    config = DEFAULT_CONFIG._replace(parametrize_values_type=values_cfg_type)\n    assert_not_error(ParametrizeVisitor, code, config=config)\n\n\n@pytest.mark.parametrize(\n    (\"values_cfg_type\", \"rows_cfg_type\", \"values\"),\n    [\n        (\n            ParametrizeValuesType.LIST,\n            ParametrizeValuesRowType.LIST,\n            VALUES_LIST_OF_LISTS,\n        ),\n        (\n            ParametrizeValuesType.TUPLE,\n            ParametrizeValuesRowType.LIST,\n            VALUES_TUPLE_OF_LISTS,\n        ),\n        (\n            ParametrizeValuesType.LIST,\n            ParametrizeValuesRowType.TUPLE,\n            VALUES_LIST_OF_TUPLES,\n        ),\n        (\n            ParametrizeValuesType.TUPLE,\n            ParametrizeValuesRowType.TUPLE,\n            VALUES_TUPLE_OF_TUPLES,\n        ),\n    ],\n)\ndef test_ok_multiple(values_cfg_type, rows_cfg_type, values):\n    code = f\"\"\"\n        import pytest\n\n        pytest.mark.parametrize(\n            ('name1', 'name2'),\n            {values!r},\n        )\n    \"\"\"\n    config = DEFAULT_CONFIG._replace(\n        parametrize_values_type=values_cfg_type,\n        parametrize_values_row_type=rows_cfg_type,\n    )\n    assert_not_error(ParametrizeVisitor, code, config=config)\n\n\n@pytest.mark.parametrize(\n    (\"values_cfg_type\", \"values\"),\n    [\n        (ParametrizeValuesType.LIST, VALUES_TUPLE),\n        (ParametrizeValuesType.TUPLE, VALUES_LIST),\n    ],\n)\ndef test_error_single(values_cfg_type, values):\n    code = f\"\"\"\n        import pytest\n\n        pytest.mark.parametrize(\n            'name',\n            {values!r},\n        )\n    \"\"\"\n    config = DEFAULT_CONFIG._replace(parametrize_values_type=values_cfg_type)\n    assert_error(\n        ParametrizeVisitor,\n        code,\n        ParametrizeValuesWrongType,\n        expected_type=values_cfg_type.value,\n        config=config,\n    )\n\n\ndef test_error_single_tuple_as_decorator():\n    code = \"\"\"\n        import pytest\n\n        @pytest.mark.parametrize(\n            'name',\n            ('a', 'b', 'c'),\n        )\n        def test_smth(name):\n            pass\n    \"\"\"\n    assert_error(\n        ParametrizeVisitor,\n        code,\n        ParametrizeValuesWrongType,\n        expected_type=\"list\",\n        config=DEFAULT_CONFIG,\n    )\n\n\n@pytest.mark.parametrize(\n    (\"values_cfg_type\", \"rows_cfg_type\", \"values\"),\n    [\n        (\n            ParametrizeValuesType.LIST,\n            ParametrizeValuesRowType.LIST,\n            VALUES_LIST_OF_TUPLES,\n        ),\n        (\n            ParametrizeValuesType.LIST,\n            ParametrizeValuesRowType.LIST,\n            VALUES_TUPLE_OF_LISTS,\n        ),\n        (\n            ParametrizeValuesType.LIST,\n            ParametrizeValuesRowType.LIST,\n            VALUES_TUPLE_OF_TUPLES,\n        ),\n        (\n            ParametrizeValuesType.TUPLE,\n            ParametrizeValuesRowType.LIST,\n            VALUES_LIST_OF_LISTS,\n        ),\n        (\n            ParametrizeValuesType.TUPLE,\n            ParametrizeValuesRowType.LIST,\n            VALUES_LIST_OF_TUPLES,\n        ),\n        (\n            ParametrizeValuesType.TUPLE,\n            ParametrizeValuesRowType.LIST,\n            VALUES_TUPLE_OF_TUPLES,\n        ),\n        (\n            ParametrizeValuesType.LIST,\n            ParametrizeValuesRowType.TUPLE,\n            VALUES_LIST_OF_LISTS,\n        ),\n        (\n            ParametrizeValuesType.LIST,\n            ParametrizeValuesRowType.TUPLE,\n            VALUES_TUPLE_OF_LISTS,\n        ),\n        (\n            ParametrizeValuesType.LIST,\n            ParametrizeValuesRowType.TUPLE,\n            VALUES_TUPLE_OF_TUPLES,\n        ),\n        (\n            ParametrizeValuesType.TUPLE,\n            ParametrizeValuesRowType.TUPLE,\n            VALUES_LIST_OF_LISTS,\n        ),\n        (\n            ParametrizeValuesType.TUPLE,\n            ParametrizeValuesRowType.TUPLE,\n            VALUES_LIST_OF_TUPLES,\n        ),\n        (\n            ParametrizeValuesType.TUPLE,\n            ParametrizeValuesRowType.TUPLE,\n            VALUES_TUPLE_OF_LISTS,\n        ),\n    ],\n)\ndef test_error_multiple(values_cfg_type, rows_cfg_type, values):\n    code = f\"\"\"\n        import pytest\n\n        pytest.mark.parametrize(\n            ('name1', 'name2'),\n            {values!r},\n        )\n    \"\"\"\n    config = DEFAULT_CONFIG._replace(\n        parametrize_values_type=values_cfg_type,\n        parametrize_values_row_type=rows_cfg_type,\n    )\n    assert_error(\n        ParametrizeVisitor,\n        code,\n        ParametrizeValuesWrongType,\n        expected_type=_get_expected_type_str(values_cfg_type, rows_cfg_type),\n        config=config,\n    )\n\n\n@pytest.mark.parametrize(\"values_cfg_type\", list(ParametrizeValuesType))\n@pytest.mark.parametrize(\"rows_cfg_type\", list(ParametrizeValuesRowType))\n@pytest.mark.parametrize(\"values\", [VALUES_LIST_OF_MIXED, VALUES_TUPLE_OF_MIXED])\ndef test_error_multiple_mixed(values_cfg_type, rows_cfg_type, values):\n    code = f\"\"\"\n        import pytest\n\n        pytest.mark.parametrize(\n            ('name1', 'name2'),\n            {values!r},\n        )\n    \"\"\"\n    config = DEFAULT_CONFIG._replace(\n        parametrize_values_type=values_cfg_type,\n        parametrize_values_row_type=rows_cfg_type,\n    )\n    assert_error(\n        ParametrizeVisitor,\n        code,\n        ParametrizeValuesWrongType,\n        expected_type=_get_expected_type_str(values_cfg_type, rows_cfg_type),\n        config=config,\n    )\n"
  },
  {
    "path": "tests/test_PT008_patch_with_lambda.py",
    "content": "import sys\n\nimport pytest\nfrom flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.errors import PatchWithLambda\nfrom flake8_pytest_style.visitors import PatchVisitor\n\nHAS_POSITIONAL_ONLY_ARGS = sys.version_info >= (3, 8)\n\nparametrize_code_template = pytest.mark.parametrize(\n    \"code_template\",\n    [\n        \"mocker.patch('module.name', {})\",\n        \"module_mocker.patch('module.name', {})\",\n        \"mocker.patch.object(obj, 'attr', {})\",\n        \"module_mocker.patch.object(obj, 'attr', {})\",\n    ],\n    ids=(\n        \"mocker.patch\",\n        \"module_mocker.patch\",\n        \"mocker.patch.object\",\n        \"module_mocker.patch.object\",\n    ),\n)\n\n\n@parametrize_code_template\n@pytest.mark.parametrize(\n    \"patch_with\",\n    [\n        \"not_lambda\",\n        \"return_value=None\",\n        \"lambda x, y: x\",\n        \"lambda *args: args\",\n        \"lambda **kwargs: kwargs\",\n        pytest.param(\n            \"lambda x, /, y: x\",\n            marks=[\n                pytest.mark.skipif(\n                    not HAS_POSITIONAL_ONLY_ARGS, reason=f\"unsupported in {sys.version}\"\n                )\n            ],\n        ),\n    ],\n)\ndef test_ok(code_template, patch_with):\n    code = code_template.format(patch_with)\n    assert_not_error(PatchVisitor, code)\n\n\n@parametrize_code_template\n@pytest.mark.parametrize(\n    \"patch_with\", [\"lambda: None\", \"lambda x, y: None\", \"lambda *args, **kwargs: None\"]\n)\ndef test_error(code_template, patch_with):\n    code = code_template.format(patch_with)\n    assert_error(PatchVisitor, code, PatchWithLambda)\n"
  },
  {
    "path": "tests/test_PT009_unittest_assertion.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.errors import UnittestAssertion\nfrom flake8_pytest_style.visitors import UnittestAssertionVisitor\n\n\ndef test_ok_no_parameters():\n    code = \"\"\"\n        import pytest\n\n        def test_xxx():\n            assert 1 == 1\n    \"\"\"\n    assert_not_error(UnittestAssertionVisitor, code)\n\n\ndef test_error():\n    code = \"\"\"\n        import pytest\n\n        def test_xxx():\n            self.assertEqual(1, 1)\n    \"\"\"\n    assert_error(\n        UnittestAssertionVisitor, code, UnittestAssertion, assertion=\"assertEqual\"\n    )\n"
  },
  {
    "path": "tests/test_PT010_raises_without_exception.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import RaisesWithoutException\nfrom flake8_pytest_style.visitors import RaisesVisitor\n\n\ndef test_ok():\n    code = \"\"\"\n        import pytest\n\n        def test_something():\n            with pytest.raises(UnicodeError):\n                pass\n    \"\"\"\n    assert_not_error(RaisesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_error():\n    code = \"\"\"\n        import pytest\n\n        def test_something():\n            with pytest.raises():\n                pass\n    \"\"\"\n    assert_error(RaisesVisitor, code, RaisesWithoutException, config=DEFAULT_CONFIG)\n"
  },
  {
    "path": "tests/test_PT011_raises_too_broad.py",
    "content": "import pytest\nfrom flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import RaisesTooBroad\nfrom flake8_pytest_style.visitors import RaisesVisitor\n\n\ndef test_ok():\n    code = \"\"\"\n        import pytest\n\n        def test_something():\n            with pytest.raises(ValueError, match=\"Can't divide by 0\"):\n                raise ValueError(\"Can't divide by 0\")\n    \"\"\"\n    assert_not_error(RaisesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_different_error_from_config():\n    code = \"\"\"\n        import pytest\n\n        def test_something():\n            with pytest.raises(ZeroDivisionError):\n                raise ZeroDivisionError(\"Can't divide by 0\")\n    \"\"\"\n    assert_not_error(RaisesVisitor, code, config=DEFAULT_CONFIG)\n\n\n@pytest.mark.parametrize(\"exception\", [\"ValueError\", \"socket.error\"])\ndef test_error_no_argument_given(exception):\n    code = f\"\"\"\n        import pytest\n\n        def test_something():\n            with pytest.raises({exception}):\n                raise ValueError(\"Can't divide 1 by 0\")\n    \"\"\"\n    assert_error(\n        RaisesVisitor,\n        code,\n        RaisesTooBroad,\n        config=DEFAULT_CONFIG,\n        exception=exception,\n    )\n\n\n@pytest.mark.parametrize(\"match\", [\"None\", '\"\"', 'f\"\"'])\ndef test_error_match_is_empty(match):\n    code = f\"\"\"\n        import pytest\n\n        def test_something():\n            with pytest.raises(ValueError, match={match}):\n                raise ValueError(\"Can't divide 1 by 0\")\n    \"\"\"\n    assert_error(\n        RaisesVisitor,\n        code,\n        RaisesTooBroad,\n        config=DEFAULT_CONFIG,\n        exception=\"ValueError\",\n    )\n"
  },
  {
    "path": "tests/test_PT012_raises_with_multiple_statements.py",
    "content": "import pytest\nfrom flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import RaisesWithMultipleStatements\nfrom flake8_pytest_style.visitors import RaisesVisitor\n\n\ndef test_ok():\n    code = \"\"\"\n        def test_something():\n            with pytest.raises(AttributeError):\n                [].size\n    \"\"\"\n    assert_not_error(RaisesVisitor, code, config=DEFAULT_CONFIG)\n\n\n@pytest.mark.parametrize(\"maybe_async\", [\"\", \"async \"])\ndef test_ok_trivial_with(maybe_async):\n    code = f\"\"\"\n        async def test_something():\n            with pytest.raises(AttributeError):\n                {maybe_async}with context_manager_under_test():\n                    pass\n    \"\"\"\n    assert_not_error(RaisesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_error_multiple_statements():\n    code = \"\"\"\n        def test_something():\n            with pytest.raises(AttributeError):\n                len([])\n                [].size\n    \"\"\"\n    assert_error(\n        RaisesVisitor, code, RaisesWithMultipleStatements, config=DEFAULT_CONFIG\n    )\n\n\n@pytest.mark.parametrize(\n    \"statement\", [\"if\", \"for i in\", \"async for i in\", \"while\", \"with\", \"async with\"]\n)\ndef test_error_complex_statement(statement):\n    code = f\"\"\"\n        async def test_something():\n            with pytest.raises(AttributeError):\n                {statement} True:\n                    [].size\n    \"\"\"\n    assert_error(\n        RaisesVisitor, code, RaisesWithMultipleStatements, config=DEFAULT_CONFIG\n    )\n\n\ndef test_error_try():\n    code = \"\"\"\n        def test_something():\n            with pytest.raises(AttributeError):\n                try:\n                    [].size\n                except:\n                    raise\n    \"\"\"\n    assert_error(\n        RaisesVisitor, code, RaisesWithMultipleStatements, config=DEFAULT_CONFIG\n    )\n"
  },
  {
    "path": "tests/test_PT013_incorrect_pytest_import.py",
    "content": "import pytest\nfrom flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.errors import IncorrectPytestImport\nfrom flake8_pytest_style.visitors.imports import ImportsVisitor\n\n\n@pytest.mark.parametrize(\n    \"code\",\n    [\n        \"import pytest\",\n        \"import pytest as pytest\",\n        \"from notpytest import fixture\",\n        \"from . import fixture\",\n        \"from .pytest import fixture\",\n    ],\n)\ndef test_ok(code):\n    assert_not_error(ImportsVisitor, code)\n\n\n@pytest.mark.parametrize(\n    \"code\",\n    [\n        \"import pytest as other_name\",\n        \"from pytest import fixture\",\n        \"from pytest import fixture as other_name\",\n    ],\n)\ndef test_error(code):\n    assert_error(ImportsVisitor, code, IncorrectPytestImport)\n"
  },
  {
    "path": "tests/test_PT014_duplicate_parametrize_test_cases.py",
    "content": "from flake8_plugin_utils import assert_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import DuplicateParametrizeTestCases\nfrom flake8_pytest_style.visitors import ParametrizeVisitor\n\n\ndef test_error():\n    code = \"\"\"\n        pytest.mark.parametrize(\n            'name',\n            [\n                {1: 2, 3: {*other_set, 4, 5}, **otherdict},\n                {x: y},\n                {3: {5, *other_set, 4}, 1: 2, **otherdict},\n            ]\n        )\n    \"\"\"\n    assert_error(\n        ParametrizeVisitor,\n        code,\n        DuplicateParametrizeTestCases,\n        indexes=(1, 3),\n        config=DEFAULT_CONFIG,\n    )\n"
  },
  {
    "path": "tests/test_PT015_assert_always_false.py",
    "content": "import pytest\nfrom flake8_plugin_utils.utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.errors import AssertAlwaysFalse\nfrom flake8_pytest_style.visitors import FailVisitor\n\n\ndef test_ok():\n    code = \"\"\"\n        def test_xxx():\n            assert [0]\n    \"\"\"\n    assert_not_error(FailVisitor, code)\n\n\n@pytest.mark.parametrize(\n    \"falsy_constant\",\n    [\n        \"None\",\n        \"False\",\n        \"0\",\n        \"0.0\",\n        '\"\"',\n        'f\"\"',\n        \"[]\",\n        \"()\",\n        \"{}\",\n        \"list()\",\n        \"set()\",\n        \"tuple()\",\n        \"dict()\",\n        \"frozenset()\",\n        \"list([])\",\n        \"set(set())\",\n        'tuple(\"\")',\n    ],\n)\ndef test_error(falsy_constant):\n    code = f\"\"\"\n        def test_xxx():\n            assert {falsy_constant}\n    \"\"\"\n    assert_error(FailVisitor, code, AssertAlwaysFalse)\n"
  },
  {
    "path": "tests/test_PT016_fail_without_message.py",
    "content": "import pytest\nfrom flake8_plugin_utils.utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.errors import FailWithoutMessage\nfrom flake8_pytest_style.visitors import FailVisitor\n\n\ndef test_ok_arg():\n    code = \"\"\"\n        def test_xxx():\n            pytest.fail('this is a failure')\n    \"\"\"\n    assert_not_error(FailVisitor, code)\n\n\ndef test_ok_kwarg():\n    code = \"\"\"\n        def test_xxx():\n            pytest.fail(reason='this is a failure')\n    \"\"\"\n    assert_not_error(FailVisitor, code)\n\n\ndef test_ok_kwarg_legacy():\n    code = \"\"\"\n        def test_xxx():\n            pytest.fail(msg='this is a failure')\n    \"\"\"\n    assert_not_error(FailVisitor, code)\n\n\n@pytest.mark.parametrize(\n    \"args\", [\"\", '\"\"', 'f\"\"', 'reason=\"\"', 'reason=f\"\"', 'msg=\"\"', 'msg=f\"\"']\n)\ndef test_error(args):\n    code = f\"\"\"\n        def test_xxx():\n            pytest.fail({args})\n    \"\"\"\n    assert_error(FailVisitor, code, FailWithoutMessage)\n"
  },
  {
    "path": "tests/test_PT017_assert_in_except.py",
    "content": "from flake8_plugin_utils.utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import AssertInExcept\nfrom flake8_pytest_style.visitors import TryExceptVisitor\n\n\ndef test_ok():\n    code = \"\"\"\n        def test_xxx():\n            try:\n                something()\n            except Exception as e:\n                something_else()\n\n            with pytest.raises(ZeroDivisionError) as e:\n                1 / 0\n            assert e.value.message\n    \"\"\"\n    assert_not_error(TryExceptVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_error():\n    code = \"\"\"\n        def test_xxx():\n            try:\n                something()\n            except Exception as e:\n                assert e.message, 'blah blah'\n    \"\"\"\n    assert_error(\n        TryExceptVisitor, code, AssertInExcept, name=\"e\", config=DEFAULT_CONFIG\n    )\n"
  },
  {
    "path": "tests/test_PT018_composite_assertion.py",
    "content": "import pytest\nfrom flake8_plugin_utils.utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.errors import CompositeAssertion\nfrom flake8_pytest_style.visitors.assertion import AssertionVisitor\n\n\ndef test_ok():\n    code = \"\"\"\n        def test_xxx():\n            assert something\n            assert something or something_else\n            assert something or something_else and something_third\n            assert not (something and something_else)\n    \"\"\"\n    assert_not_error(AssertionVisitor, code)\n\n\n@pytest.mark.parametrize(\n    \"condition\",\n    [\n        \"something and something_else\",\n        \"something and something_else and something_third\",\n        \"something and not something_else\",\n        \"something and (something_else or something_third)\",\n        \"not (something or something_else)\",\n        \"not (something or something_else or something_third)\",\n        \"not (something or something_else and something_third)\",\n    ],\n)\ndef test_error(condition):\n    code = f\"\"\"\n        def test_xxx():\n            assert {condition}\n    \"\"\"\n    assert_error(AssertionVisitor, code, CompositeAssertion)\n"
  },
  {
    "path": "tests/test_PT019_fixture_param_without_value.py",
    "content": "from flake8_plugin_utils.utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.errors import FixtureParamWithoutValue\nfrom flake8_pytest_style.visitors import TFunctionsVisitor\n\n\ndef test_ok_good_param_name():\n    code = \"\"\"\n        def test_xxx(fixture):\n            pass\n    \"\"\"\n    assert_not_error(TFunctionsVisitor, code)\n\n\ndef test_ok_non_test_function():\n    code = \"\"\"\n        def xxx(_param):\n            pass\n    \"\"\"\n    assert_not_error(TFunctionsVisitor, code)\n\n\ndef test_error_arg():\n    code = \"\"\"\n        def test_xxx(_fixture):\n            pass\n    \"\"\"\n    assert_error(TFunctionsVisitor, code, FixtureParamWithoutValue, name=\"_fixture\")\n\n\ndef test_error_kwonly():\n    code = \"\"\"\n        def test_xxx(*, _fixture):\n            pass\n    \"\"\"\n    assert_error(TFunctionsVisitor, code, FixtureParamWithoutValue, name=\"_fixture\")\n"
  },
  {
    "path": "tests/test_PT020_deprecated_yield_fixture.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import DeprecatedYieldFixture\nfrom flake8_pytest_style.visitors import FixturesVisitor\n\n# make the configs independent of the actual default\n_CONFIG_WITHOUT_PARENS = DEFAULT_CONFIG._replace(fixture_parentheses=False)\n_CONFIG_WITH_PARENS = DEFAULT_CONFIG._replace(fixture_parentheses=True)\n\n\ndef test_ok_no_parameters():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture()\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=_CONFIG_WITH_PARENS)\n\n\ndef test_ok_without_parens():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=_CONFIG_WITHOUT_PARENS)\n\n\ndef test_error_without_parens():\n    code = \"\"\"\n        import pytest\n\n        @pytest.yield_fixture\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_error(\n        FixturesVisitor, code, DeprecatedYieldFixture, config=_CONFIG_WITHOUT_PARENS\n    )\n\n\ndef test_error_with_parens():\n    code = \"\"\"\n        import pytest\n\n        @pytest.yield_fixture()\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_error(\n        FixturesVisitor, code, DeprecatedYieldFixture, config=_CONFIG_WITH_PARENS\n    )\n"
  },
  {
    "path": "tests/test_PT021_fixture_finalizer_callback.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import FixtureFinalizerCallback\nfrom flake8_pytest_style.visitors import FixturesVisitor\n\n\ndef test_ok_return():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_yield():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture():\n            resource = acquire_resource()\n            yield resource\n            resource.release()\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_other_request():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture():\n            request = get_request()\n            request.addfinalizer(finalizer)\n            return request\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_other_function():\n    # factory fixtures are a tricky use-case where addfinalizer cannot be replaced\n    # inspired by tls_http_server fixture in cherrypy/cheroot\n    code = \"\"\"\n        import functools\n        import pytest\n\n        def create_resource(arg, request):\n            resource = Resource(arg)\n            request.addfinalizer(resource.release)\n            return resource\n\n        @pytest.fixture\n        def resource_factory(request):\n            return functools.partial(create_resource, request=request)\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_nested_function():\n    # https://github.com/m-burst/flake8-pytest-style/issues/46\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def resource_factory(request):\n            def create_resource(arg) -> Resource:\n                resource = Resource(arg)\n                request.addfinalizer(resource.release)\n                return resource\n            return create_resource\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_error_return():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture(request):\n            resource = acquire_resource()\n            request.addfinalizer(resource.release)\n            return resource\n    \"\"\"\n    assert_error(FixturesVisitor, code, FixtureFinalizerCallback, config=DEFAULT_CONFIG)\n\n\ndef test_error_yield():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture(request):\n            resource = acquire_resource()\n            request.addfinalizer(resource.release)\n            yield resource\n            resource  # prevent PT022\n    \"\"\"\n    assert_error(FixturesVisitor, code, FixtureFinalizerCallback, config=DEFAULT_CONFIG)\n"
  },
  {
    "path": "tests/test_PT022_useless_yield_fixture.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import UselessYieldFixture\nfrom flake8_pytest_style.visitors import FixturesVisitor\n\n# Skipping basic OK tests because we have A LOT of valid fixtures in other\n# test files\n\n\ndef test_ok_complex_logic():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture():\n            if some_condition:\n                resource = acquire_resource()\n                yield resource\n                resource.release()\n                return\n            yield None\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_error():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        def my_fixture():\n            resource = acquire_resource()\n            yield resource\n    \"\"\"\n    assert_error(\n        FixturesVisitor,\n        code,\n        UselessYieldFixture,\n        name=\"my_fixture\",\n        config=DEFAULT_CONFIG,\n    )\n"
  },
  {
    "path": "tests/test_PT023_incorrect_mark_parentheses_style.py",
    "content": "import pytest\nfrom flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import IncorrectMarkParenthesesStyle\nfrom flake8_pytest_style.visitors import MarksVisitor\n\n_CONFIG_WITHOUT_PARENS = DEFAULT_CONFIG._replace(mark_parentheses=False)\n_CONFIG_WITH_PARENS = DEFAULT_CONFIG._replace(mark_parentheses=True)\n\n\nSAMPLES_WITHOUT_PARENTHESES = [\n    pytest.param(\n        \"\"\"\n            import pytest\n\n            @pytest.mark.foo\n            def test_something():\n                pass\n        \"\"\",\n        id=\"function\",\n    ),\n    pytest.param(\n        \"\"\"\n            import pytest\n\n            @pytest.mark.foo\n            class TestClass:\n                def test_something():\n                    pass\n        \"\"\",\n        id=\"class\",\n    ),\n    pytest.param(\n        \"\"\"\n            import pytest\n\n            class TestClass:\n                @pytest.mark.foo\n                def test_something():\n                    pass\n        \"\"\",\n        id=\"method\",\n    ),\n    pytest.param(\n        \"\"\"\n            import pytest\n\n            class TestClass:\n                @pytest.mark.foo\n                class TestNestedClass:\n                    def test_something():\n                        pass\n        \"\"\",\n        id=\"nested_class\",\n    ),\n    pytest.param(\n        \"\"\"\n            import pytest\n\n            class TestClass:\n                class TestNestedClass:\n                    @pytest.mark.foo\n                    def test_something():\n                        pass\n        \"\"\",\n        id=\"nested_class_method\",\n    ),\n]\n\nSAMPLES_WITH_PARENTHESES = [\n    pytest.param(\n        \"\"\"\n            import pytest\n\n            @pytest.mark.foo()\n            def test_something():\n                pass\n        \"\"\",\n        id=\"function\",\n    ),\n    pytest.param(\n        \"\"\"\n            import pytest\n\n            @pytest.mark.foo()\n            class TestClass:\n                def test_something():\n                    pass\n        \"\"\",\n        id=\"class\",\n    ),\n    pytest.param(\n        \"\"\"\n            import pytest\n\n            class TestClass:\n                @pytest.mark.foo()\n                def test_something():\n                    pass\n        \"\"\",\n        id=\"method\",\n    ),\n    pytest.param(\n        \"\"\"\n            import pytest\n\n            class TestClass:\n                @pytest.mark.foo()\n                class TestNestedClass:\n                    def test_something():\n                        pass\n        \"\"\",\n        id=\"nested_class\",\n    ),\n    pytest.param(\n        \"\"\"\n            import pytest\n\n            class TestClass:\n                class TestNestedClass:\n                    @pytest.mark.foo()\n                    def test_something():\n                        pass\n        \"\"\",\n        id=\"nested_class_method\",\n    ),\n]\n\n\n@pytest.mark.parametrize(\"mark_parentheses\", [True, False])\ndef test_ok_with_parameters_regardless_of_config(mark_parentheses: bool):\n    code = \"\"\"\n        import pytest\n\n        @pytest.mark.foo(scope='module')\n        def test_something():\n            pass\n    \"\"\"\n    config = DEFAULT_CONFIG._replace(mark_parentheses=mark_parentheses)\n    assert_not_error(MarksVisitor, code, config=config)\n\n\n@pytest.mark.parametrize(\"code\", SAMPLES_WITHOUT_PARENTHESES)\ndef test_ok_without_parens(code: str):\n    assert_not_error(MarksVisitor, code, config=_CONFIG_WITHOUT_PARENS)\n\n\n@pytest.mark.parametrize(\"code\", SAMPLES_WITH_PARENTHESES)\ndef test_ok_with_parens(code: str):\n    assert_not_error(MarksVisitor, code, config=_CONFIG_WITH_PARENS)\n\n\n@pytest.mark.parametrize(\"code\", SAMPLES_WITHOUT_PARENTHESES)\ndef test_error_without_parens(code: str):\n    assert_error(\n        MarksVisitor,\n        code,\n        IncorrectMarkParenthesesStyle,\n        config=_CONFIG_WITH_PARENS,\n        mark_name=\"foo\",\n        expected_parens=\"()\",\n        actual_parens=\"\",\n    )\n\n\n@pytest.mark.parametrize(\"code\", SAMPLES_WITH_PARENTHESES)\ndef test_error_with_parens(code: str):\n    assert_error(\n        MarksVisitor,\n        code,\n        IncorrectMarkParenthesesStyle,\n        config=_CONFIG_WITHOUT_PARENS,\n        mark_name=\"foo\",\n        expected_parens=\"\",\n        actual_parens=\"()\",\n    )\n"
  },
  {
    "path": "tests/test_PT024_unncessary_asyncio_mark_on_fixture.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import UnnecessaryAsyncioMarkOnFixture\nfrom flake8_pytest_style.visitors import FixturesVisitor\n\n\ndef test_ok_not_fixture():\n    code = \"\"\"\n        import pytest\n\n        @pytest.mark.asyncio()\n        async def test_something():\n            pass\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_not_fixture_no_parens():\n    code = \"\"\"\n        import pytest\n\n        @pytest.mark.asyncio\n        async def test_something():\n            pass\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_error_before():\n    code = \"\"\"\n        import pytest\n\n        @pytest.mark.asyncio()\n        @pytest.fixture\n        async def my_fixture():\n            return 0\n    \"\"\"\n    assert_error(\n        FixturesVisitor, code, UnnecessaryAsyncioMarkOnFixture, config=DEFAULT_CONFIG\n    )\n\n\ndef test_error_before_no_parens():\n    code = \"\"\"\n        import pytest\n\n        @pytest.mark.asyncio\n        @pytest.fixture\n        async def my_fixture():\n            return 0\n    \"\"\"\n    assert_error(\n        FixturesVisitor, code, UnnecessaryAsyncioMarkOnFixture, config=DEFAULT_CONFIG\n    )\n\n\ndef test_error_after():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        @pytest.mark.asyncio()\n        async def my_fixture():\n            return 0\n    \"\"\"\n    assert_error(\n        FixturesVisitor, code, UnnecessaryAsyncioMarkOnFixture, config=DEFAULT_CONFIG\n    )\n\n\ndef test_error_after_no_parens():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        @pytest.mark.asyncio\n        async def my_fixture():\n            return 0\n    \"\"\"\n    assert_error(\n        FixturesVisitor, code, UnnecessaryAsyncioMarkOnFixture, config=DEFAULT_CONFIG\n    )\n"
  },
  {
    "path": "tests/test_PT025_erroneous_usefixtures_on_fixture.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import ErroneousUseFixturesOnFixture\nfrom flake8_pytest_style.visitors import FixturesVisitor\n\n\ndef test_ok_not_fixture():\n    code = \"\"\"\n        import pytest\n\n        @pytest.mark.usefixtures('a')\n        def test_something():\n            pass\n    \"\"\"\n    assert_not_error(FixturesVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_error_before():\n    code = \"\"\"\n        import pytest\n\n        @pytest.mark.usefixtures('a')\n        @pytest.fixture\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_error(\n        FixturesVisitor,\n        code,\n        ErroneousUseFixturesOnFixture,\n        config=DEFAULT_CONFIG,\n    )\n\n\ndef test_error_after():\n    code = \"\"\"\n        import pytest\n\n        @pytest.fixture\n        @pytest.mark.usefixtures('a')\n        def my_fixture():\n            return 0\n    \"\"\"\n    assert_error(\n        FixturesVisitor,\n        code,\n        ErroneousUseFixturesOnFixture,\n        config=DEFAULT_CONFIG,\n    )\n"
  },
  {
    "path": "tests/test_PT026_usefixtures_without_parameters.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import UseFixturesWithoutParameters\nfrom flake8_pytest_style.visitors import MarksVisitor\n\n\ndef test_ok():\n    code = \"\"\"\n        import pytest\n\n        @pytest.mark.usefixtures('a')\n        def test_something():\n            pass\n    \"\"\"\n    assert_not_error(MarksVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_another_mark_with_parens():\n    code = \"\"\"\n        import pytest\n\n        @pytest.mark.foo()\n        def test_something():\n            pass\n    \"\"\"\n    config = DEFAULT_CONFIG._replace(mark_parentheses=True)\n    assert_not_error(MarksVisitor, code, config=config)\n\n\ndef test_ok_another_mark_no_parens():\n    code = \"\"\"\n        import pytest\n\n        @pytest.mark.foo\n        def test_something():\n            pass\n    \"\"\"\n    config = DEFAULT_CONFIG._replace(mark_parentheses=False)\n    assert_not_error(MarksVisitor, code, config=config)\n\n\ndef test_error_with_parens():\n    code = \"\"\"\n        import pytest\n\n        @pytest.mark.usefixtures()\n        def test_something():\n            pass\n    \"\"\"\n    config = DEFAULT_CONFIG._replace(mark_parentheses=True)\n    assert_error(MarksVisitor, code, UseFixturesWithoutParameters, config=config)\n\n\ndef test_error_no_parens():\n    code = \"\"\"\n        import pytest\n\n        @pytest.mark.usefixtures\n        def test_something():\n            pass\n    \"\"\"\n    config = DEFAULT_CONFIG._replace(mark_parentheses=False)\n    assert_error(MarksVisitor, code, UseFixturesWithoutParameters, config=config)\n"
  },
  {
    "path": "tests/test_PT027_unittest_raises_assertion.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.errors import UnittestRaisesAssertion\nfrom flake8_pytest_style.visitors import UnittestAssertionVisitor\n\n\ndef test_ok_no_parameters():\n    code = \"\"\"\n        import pytest\n\n        def test_xxx():\n            with pytest.raises(ValueError):\n                raise ValueError()\n    \"\"\"\n    assert_not_error(UnittestAssertionVisitor, code)\n\n\ndef test_error():\n    code = \"\"\"\n        import pytest\n\n        def test_xxx():\n            with self.assertRaises(ValueError):\n                raise ValueError()\n    \"\"\"\n    assert_error(\n        UnittestAssertionVisitor,\n        code,\n        UnittestRaisesAssertion,\n        assertion=\"assertRaises\",\n    )\n"
  },
  {
    "path": "tests/test_PT028_test_function_argument_with_default.py",
    "content": "import ast\nimport textwrap\n\nfrom flake8_plugin_utils.utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.errors import TFunctionArgumentWithDefault\nfrom flake8_pytest_style.visitors import TFunctionsVisitor\n\n\ndef test_ok():\n    code = \"\"\"\n        def test_xxx(fixture1, /, fixture2, *, fixture3):\n            pass\n    \"\"\"\n    assert_not_error(TFunctionsVisitor, code)\n\n\ndef test_ok_non_test_function():\n    code = \"\"\"\n        def xxx(posonly1, posonly2=2, /, arg=3, *, kwonly=4):\n            pass\n    \"\"\"\n    assert_not_error(TFunctionsVisitor, code)\n\n\ndef test_error_posonly():\n    code = \"\"\"\n        def test_xxx(posonly1, posonly2=2, /):\n            pass\n    \"\"\"\n    assert_error(\n        TFunctionsVisitor,\n        code,\n        TFunctionArgumentWithDefault,\n        name=\"test_xxx\",\n        arg=\"posonly2\",\n    )\n\n\ndef test_error_arg():\n    code = \"\"\"\n        def test_xxx(arg1, arg2=2):\n            pass\n    \"\"\"\n    assert_error(\n        TFunctionsVisitor,\n        code,\n        TFunctionArgumentWithDefault,\n        name=\"test_xxx\",\n        arg=\"arg2\",\n    )\n\n\ndef test_error_kwonly():\n    code = \"\"\"\n        def test_xxx(*, kwonly1, kwonly2=2):\n            pass\n    \"\"\"\n    assert_error(\n        TFunctionsVisitor,\n        code,\n        TFunctionArgumentWithDefault,\n        name=\"test_xxx\",\n        arg=\"kwonly2\",\n    )\n\n\ndef test_error_multiple():\n    code = \"\"\"\n        def test_xxx(\n            posonly=1,\n            /,\n            arg=2,\n            *,\n            kwonly=3,\n        ):\n            pass\n    \"\"\"\n    # flake8-plugin-utils does not allow multiple errors in a single test\n    visitor = TFunctionsVisitor()\n    visitor.visit(ast.parse(textwrap.dedent(code)))\n    assert len(visitor.errors) == 3\n    posonly_error, arg_error, kwonly_error = visitor.errors\n\n    assert isinstance(posonly_error, TFunctionArgumentWithDefault)\n    assert posonly_error.message == TFunctionArgumentWithDefault.formatted_message(\n        name=\"test_xxx\", arg=\"posonly\"\n    )\n    assert posonly_error.lineno == 3\n\n    assert isinstance(arg_error, TFunctionArgumentWithDefault)\n    assert arg_error.message == TFunctionArgumentWithDefault.formatted_message(\n        name=\"test_xxx\", arg=\"arg\"\n    )\n    assert arg_error.lineno == 5\n\n    assert isinstance(kwonly_error, TFunctionArgumentWithDefault)\n    assert kwonly_error.message == TFunctionArgumentWithDefault.formatted_message(\n        name=\"test_xxx\", arg=\"kwonly\"\n    )\n    assert kwonly_error.lineno == 7\n"
  },
  {
    "path": "tests/test_PT029_warns_without_warning.py",
    "content": "from flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import WarnsWithoutException\nfrom flake8_pytest_style.visitors import WarnsVisitor\n\n\ndef test_ok():\n    code = \"\"\"\n        import pytest\n\n        def test_something():\n            with pytest.warns(UnicodeError):\n                pass\n    \"\"\"\n    assert_not_error(WarnsVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_error():\n    code = \"\"\"\n        import pytest\n\n        def test_something():\n            with pytest.warns():\n                pass\n    \"\"\"\n    assert_error(WarnsVisitor, code, WarnsWithoutException, config=DEFAULT_CONFIG)\n"
  },
  {
    "path": "tests/test_PT030_warns_too_broad.py",
    "content": "import pytest\nfrom flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import WarnsTooBroad\nfrom flake8_pytest_style.visitors import WarnsVisitor\n\n\ndef test_ok():\n    code = \"\"\"\n        import pytest\n        import warnings\n\n        def test_something():\n            with pytest.warns(UserWarning, match=\"foo\"):\n                warnings.warn(\"foo\", UserWarning)\n    \"\"\"\n    assert_not_error(WarnsVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_ok_different_error_from_config():\n    code = \"\"\"\n        import pytest\n        import warnings\n\n        def test_something():\n            with pytest.warns(BytesWarning):\n                warnings.warn(\"foo\", UserWarning)\n    \"\"\"\n    assert_not_error(WarnsVisitor, code, config=DEFAULT_CONFIG)\n\n\n@pytest.mark.parametrize(\"warning\", [\"Warning\", \"UserWarning\"])\ndef test_error_no_argument_given(warning):\n    code = f\"\"\"\n        import pytest\n        import warnings\n\n        def test_something():\n            with pytest.warns({warning}):\n                warnings.warn(\"foo\", UserWarning)\n    \"\"\"\n    assert_error(\n        WarnsVisitor,\n        code,\n        WarnsTooBroad,\n        config=DEFAULT_CONFIG,\n        warning=warning,\n    )\n\n\n@pytest.mark.parametrize(\"match\", [\"None\", '\"\"', 'f\"\"'])\ndef test_error_match_is_empty(match):\n    code = f\"\"\"\n        import pytest\n        import warnings\n\n        def test_something():\n            with pytest.warns(UserWarning, match={match}):\n                warnings.warn(\"foo\", UserWarning)\n    \"\"\"\n    assert_error(\n        WarnsVisitor,\n        code,\n        WarnsTooBroad,\n        config=DEFAULT_CONFIG,\n        warning=\"UserWarning\",\n    )\n"
  },
  {
    "path": "tests/test_PT031_warns_with_multiple_statements.py",
    "content": "import pytest\nfrom flake8_plugin_utils import assert_error, assert_not_error\n\nfrom flake8_pytest_style.config import DEFAULT_CONFIG\nfrom flake8_pytest_style.errors import WarnsWithMultipleStatements\nfrom flake8_pytest_style.visitors import WarnsVisitor\n\n\ndef test_ok():\n    code = \"\"\"\n        def test_something():\n            with pytest.warns(BytesWarning):\n                [].size\n    \"\"\"\n    assert_not_error(WarnsVisitor, code, config=DEFAULT_CONFIG)\n\n\n@pytest.mark.parametrize(\"maybe_async\", [\"\", \"async \"])\ndef test_ok_trivial_with(maybe_async):\n    code = f\"\"\"\n        async def test_something():\n            with pytest.warns(BytesWarning):\n                {maybe_async}with context_manager_under_test():\n                    pass\n    \"\"\"\n    assert_not_error(WarnsVisitor, code, config=DEFAULT_CONFIG)\n\n\ndef test_error_multiple_statements():\n    code = \"\"\"\n        def test_something():\n            with pytest.warns(BytesWarning):\n                len([])\n                [].size\n    \"\"\"\n    assert_error(WarnsVisitor, code, WarnsWithMultipleStatements, config=DEFAULT_CONFIG)\n\n\n@pytest.mark.parametrize(\n    \"statement\", [\"if\", \"for i in\", \"async for i in\", \"while\", \"with\", \"async with\"]\n)\ndef test_error_complex_statement(statement):\n    code = f\"\"\"\n        async def test_something():\n            with pytest.warns(BytesWarning):\n                {statement} True:\n                    [].size\n    \"\"\"\n    assert_error(WarnsVisitor, code, WarnsWithMultipleStatements, config=DEFAULT_CONFIG)\n\n\ndef test_error_try():\n    code = \"\"\"\n        def test_something():\n            with pytest.warns(BytesWarning):\n                try:\n                    [].size\n                except:\n                    raise\n    \"\"\"\n    assert_error(WarnsVisitor, code, WarnsWithMultipleStatements, config=DEFAULT_CONFIG)\n"
  },
  {
    "path": "tests/test_config.py",
    "content": "from typing import List\n\nimport flake8\nimport pytest\nfrom flake8.options.manager import OptionManager\n\nfrom flake8_pytest_style.config import (\n    DEFAULT_CONFIG,\n    Config,\n    ParametrizeNamesType,\n    ParametrizeValuesRowType,\n    ParametrizeValuesType,\n)\nfrom flake8_pytest_style.plugin import PytestStylePlugin\n\n\n@pytest.fixture\ndef option_manager() -> OptionManager:\n    manager = OptionManager(\n        version=flake8.__version__,\n        plugin_versions=\"\",  # Not necessary in tests\n        parents=[],\n        formatter_names=[],\n    )\n    PytestStylePlugin.add_options(option_manager=manager)\n    return manager\n\n\ndef parse_options(manager: OptionManager, args: List[str]) -> Config:\n    namespace = manager.parse_args(args)\n    return PytestStylePlugin.parse_options_to_config(\n        manager,\n        namespace,\n        # Not sure if this is semantically correct, but this is what flake8 passes\n        # to plugin's parse_options\n        namespace.filenames,\n    )\n\n\ndef test_parse_default(option_manager):\n    assert parse_options(option_manager, []) == DEFAULT_CONFIG\n\n\ndef test_parse_raises_require_match_for(option_manager):\n    config = parse_options(\n        option_manager, [\"--pytest-raises-require-match-for\", \"ValueError,TypeError\"]\n    )\n    assert config.raises_require_match_for == [\"ValueError\", \"TypeError\"]\n\n\ndef test_parse_fixture_parentheses(option_manager):\n    config = parse_options(option_manager, [\"--pytest-fixture-no-parentheses\"])\n    assert config.fixture_parentheses is False\n\n\n@pytest.mark.parametrize(\"value\", list(ParametrizeNamesType))\ndef test_parse_parametrize_names_type(option_manager, value):\n    config = parse_options(\n        option_manager, [\"--pytest-parametrize-names-type\", value.value]\n    )\n    assert config.parametrize_names_type is value\n\n\n@pytest.mark.parametrize(\"value\", list(ParametrizeValuesType))\ndef test_parse_parametrize_values_type(option_manager, value):\n    config = parse_options(\n        option_manager, [\"--pytest-parametrize-values-type\", value.value]\n    )\n    assert config.parametrize_values_type is value\n\n\n@pytest.mark.parametrize(\"value\", list(ParametrizeValuesRowType))\ndef test_parse_parametrize_values_row_type(option_manager, value):\n    config = parse_options(\n        option_manager, [\"--pytest-parametrize-values-row-type\", value.value]\n    )\n    assert config.parametrize_values_row_type is value\n\n\n@pytest.mark.parametrize(\n    \"args\",\n    [\n        [\"--pytest-parametrize-names-type\", \"str\"],\n        [\"--pytest-parametrize-values-type\", \"str\"],\n        [\"--pytest-parametrize-values-row-type\", \"str\"],\n    ],\n)\ndef test_parse_invalid_enum_values(option_manager, args):\n    with pytest.raises(SystemExit):  # as raised by optparse\n        parse_options(option_manager, args)\n"
  },
  {
    "path": "tests/test_plugin.py",
    "content": "import importlib\nimport inspect\nimport pkgutil\nfrom collections import Counter\nfrom types import ModuleType\nfrom typing import List, Set, Type, TypeVar\n\nfrom flake8_pytest_style.plugin import PytestStylePlugin\n\nT = TypeVar(\"T\")\n\n\ndef _collect_subclasses(modules: List[ModuleType], base_class: Type[T]) -> Set[Type[T]]:\n    result = set()\n    for module in modules:\n        for _, member in inspect.getmembers(module):\n            if (\n                inspect.isclass(member)\n                and issubclass(member, base_class)\n                and member is not base_class\n            ):\n                result.add(member)\n    return result\n\n\ndef test_plugin_has_all_visitors():\n    from flake8_plugin_utils import Visitor\n\n    from flake8_pytest_style import visitors as visitors_package\n\n    visitor_module_infos = pkgutil.iter_modules(\n        visitors_package.__path__  # type: ignore\n    )\n    visitor_modules = [\n        importlib.import_module(\n            f\"{visitors_package.__name__}.{visitor_module_info.name}\"\n        )\n        for visitor_module_info in visitor_module_infos\n    ]\n    visitor_classes = _collect_subclasses(visitor_modules, Visitor)\n\n    assert set(PytestStylePlugin.visitors) == visitor_classes\n\n\ndef test_all_error_codes_are_different():\n    from flake8_plugin_utils import Error\n\n    from flake8_pytest_style import errors\n\n    error_classes = _collect_subclasses([errors], Error)\n    count_by_code = Counter(error_class.code for error_class in error_classes)\n    duplicate_error_codes = [code for code, count in count_by_code.items() if count > 1]\n    assert not duplicate_error_codes\n"
  }
]