# wemake-python-styleguide [![wemake.services](https://img.shields.io/badge/%20-wemake.services-green.svg?label=%20&logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC%2FxhBQAAAAFzUkdCAK7OHOkAAAAbUExURQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP%2F%2F%2F5TvxDIAAAAIdFJOUwAjRA8xXANAL%2Bv0SAAAADNJREFUGNNjYCAIOJjRBdBFWMkVQeGzcHAwksJnAPPZGOGAASzPzAEHEGVsLExQwE7YswCb7AFZSF3bbAAAAABJRU5ErkJggg%3D%3D)](https://wemake-services.github.io) [![Supporters](https://img.shields.io/opencollective/all/wemake-python-styleguide.svg?color=gold&label=supporters)](https://opencollective.com/wemake-python-styleguide) [![test](https://github.com/wemake-services/wemake-python-styleguide/actions/workflows/test.yml/badge.svg?branch=master&event=push)](https://github.com/wemake-services/wemake-python-styleguide/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/wemake-services/wemake-python-styleguide/branch/master/graph/badge.svg)](https://codecov.io/gh/wemake-services/wemake-python-styleguide) [![Python Version](https://img.shields.io/pypi/pyversions/wemake-python-styleguide.svg)](https://pypi.org/project/wemake-python-styleguide/) [![wemake-python-styleguide](https://img.shields.io/badge/style-wemake-000000.svg)](https://github.com/wemake-services/wemake-python-styleguide) --- Welcome to the strictest and most opinionated Python linter ever. *The best tool to teach your LLM how to write idiomatic and simple Python code!*

wemake-python-styleguide logo

`wemake-python-styleguide` is actually a [flake8](http://flake8.pycqa.org/en/latest/) plugin, the only one you will need as your [ruff](https://github.com/astral-sh/ruff) companion. Fully compatible with **ALL** rules and format conventions from `ruff`. ## Quickstart ```bash pip install wemake-python-styleguide ``` You will also need to create a `setup.cfg` file with the [configuration](https://wemake-python-styleguide.rtfd.io/en/latest/pages/usage/configuration.html). [Try it online](https://wps.orsinium.dev)! We highly recommend to also use: - [ondivi](https://wemake-python-styleguide.rtfd.io/en/latest/pages/usage/integrations/ondivi.html) for easy integration into a **legacy** codebase Additional contexts for LLMs: - https://wemake-python-styleguide.readthedocs.io/llms.txt - https://wemake-python-styleguide.readthedocs.io/llms-full.txt ## Running ```bash flake8 your_module.py --select=WPS ``` This app is still just good old `flake8`! And it won't change your existing workflow.

invocation results

See ["Usage" section](https://wemake-python-styleguide.rtfd.io/en/latest/pages/usage/setup.html) in the docs for examples and integrations. We also support [GitHub Actions](https://wemake-python-styleguide.rtfd.io/en/latest/pages/usage/integrations/github-actions.html) as first class-citizens. [Try it out](https://github.com/marketplace/actions/wemake-python-styleguide)! Can (and should!) be used with `ruff`: ```bash ruff check && ruff format flake8 . --select=WPS ``` See example `ruff` configuration in our [`pyproject.toml`](https://github.com/wemake-services/wemake-python-styleguide/blob/master/pyproject.toml#L103). ## Strict is the new cool Strict linting offers the following benefits to developers and companies: 1. Ensures consistency - no matter who works on it, the end product will always be the same dependable code 2. Helps avoid potential bugs - strict rules make sure that you don't make common mistakes 3. Efficient code reviews - each piece of code has a similar familiar style and syntax. If it passes all the checks, there's little left to review! 4. Fewer code revisions - strict linting ensures that you don't have to re-write the codebase again and again 5. Reduce code redundancy - Sometimes we write complex code as we are thinking in a certain way about a problem. The linter offers suggestions that can help simplify the code and eliminate redundant statements ## What we are about The ultimate goal of this project is to make all people write **exactly** the same `Python` code. | | flake8 | pylint | black | mypy | ruff | wemake-python-styleguide | |----------------------------|--------|--------|-------|------|------|--------------------------| | Formats code? | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | | Finds style issues? | 🤔 | ✅ | 🤔 | ❌ | ✅ | ❌ | | Finds bugs? | 🤔 | ✅ | ❌ | ✅ | ✅ | ✅ | | Finds complex code? | ❌ | 🤔 | ❌ | ❌ | ❌ | ✅ | | Has a lot of strict rules? | ❌ | 🤔 | ❌ | ❌ | ✅ | ✅ | | Has a lot of plugins? | ✅ | ❌ | ❌ | 🤔 | ❌ | ✅ | We have several primary objectives: 1. Significantly reduce the complexity of your code and make it more maintainable 2. Enforce "There should be one -- and preferably only one -- obvious way to do it" rule to coding and naming styles 3. Protect developers from possible errors and enforce best practices You can find all error codes and plugins [in the docs](https://wemake-python-styleguide.rtfd.io/en/latest/pages/usage/violations/index.html). ## What we are not We are *not* planning to do the following things: 0. Assume or check types, use `mypy` together with our linter 1. Format code or produce stylistic errors, use `ruff format` for that 2. Check for all kinds of logical bugs, write tests instead 3. Appeal to everyone. But, you can [switch off](https://wemake-python-styleguide.rtfd.io/en/latest/pages/usage/setup.html#ignoring-violations) any rules that you don't like ## Supporting us :tada: We in [wemake.services](https://github.com/wemake-services) make all our tools open-source by default, so the community can benefit from them. If you use our tools and they make your life easier and brings business value, you can return us a favor by supporting the work we do. [![Gold Tier](https://opencollective.com/wemake-python-styleguide/tiers/gold-sponsor.svg?width=890)](https://opencollective.com/wemake-python-styleguide) [![Silver Tier](https://opencollective.com/wemake-python-styleguide/tiers/silver-sponsor.svg?width=890&avatarHeight=45&button=0)](https://opencollective.com/wemake-python-styleguide) [![Bronze Tier](https://opencollective.com/wemake-python-styleguide/tiers/bronze-sponsor.svg?width=890&avatarHeight=35&button=0)](https://opencollective.com/wemake-python-styleguide) ## Show your style :sunglasses: If you use our linter - it means that your code is awesome. You can be proud of it! And you should share your accomplishment with others by including a badge in your `README` file. It looks like this: [![wemake-python-styleguide](https://img.shields.io/badge/style-wemake-000000.svg)](https://github.com/wemake-services/wemake-python-styleguide) ### Markdown ```md [![wemake-python-styleguide](https://img.shields.io/badge/style-wemake-000000.svg)](https://github.com/wemake-services/wemake-python-styleguide) ``` ### Restructured text ```rst .. image:: https://img.shields.io/badge/style-wemake-000000.svg :target: https://github.com/wemake-services/wemake-python-styleguide ``` ## Contributing We **warmly welcome** all contributions! [![List of contributors](https://opencollective.com/wemake-python-styleguide/contributors.svg?width=890&button=0)](https://github.com/wemake-services/wemake-python-styleguide/graphs/contributors) See ["Contributing"](https://wemake-python-styleguide.rtfd.io/en/latest/pages/api/index.html#contributing) section in the documentation if you want to contribute. You can start with [issues that need some help](https://github.com/wemake-services/wemake-python-styleguide/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) right now. :parser: myst_parser.sphinx_ .. toctree:: :maxdepth: 1 :caption: User guide: :hidden: pages/usage/setup.rst pages/usage/configuration.rst pages/usage/violations/index.rst pages/usage/formatter.rst pages/usage/cli.rst .. toctree:: :maxdepth: 1 :caption: Integrations: :hidden: pages/usage/integrations/index.rst .. toctree:: :maxdepth: 2 :caption: Developer's guide: :hidden: pages/api/index.rst .. toctree:: :maxdepth: 1 :caption: Changelog: :hidden: pages/changelog/index.rst Indices and tables ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` Setup ===== Remember that ``wemake-python-styleguide`` is just a ``flake8`` plugin. That is compatible with ``ruff --select=ALL`` and should be used after it. .. _installation: Installation ------------ .. code:: bash pip install wemake-python-styleguide We also recommend to use `poetry `_ instead of a default ``pip``. You might want to also install optional tools that pairs nicely with ``wemake-python-styleguide``: - :ref:`ondivi` for easy integration into a **legacy** codebase .. _usage: Required configuration ---------------------- You must either provide ``--select=WPS`` to all your ``flake8`` calls, or add ``select = WPS`` into your ``flake8`` configuration file. Running ------- To run our linter you will need to run ``flake8`` in any way you like: .. code:: bash flake8 . # runs on all python files in the current directory (recommended) flake8 your_module.py # runs on a single file flake8 your_package # runs on a single your_package See the ``flake8`` docs for `options `_ and `usage examples `_. Golden rule is to run your linter on each commit locally and inside the CI. And to fail the build if there are any style violations. Check out how we do it in our different templates: - ``django`` and ``gitlab-ci``: https://github.com/wemake-services/wemake-django-template - ``python`` package and ``travis``: https://github.com/wemake-services/wemake-python-package .. rubric:: Further reading - :ref:`Configuring and ignoring violations ` - :ref:`Introducing this linter to a legacy codebase ` Command line tool ================= .. versionadded:: 1.1.0 WPS has a command-line utility named ``wps`` Here are listed all the subcommands it has. .. rubric:: ``wps explain`` This command can be used to get description of violation. It will be the same description that is located on the website. Syntax: ``wps explain `` Examples: .. code:: text $ wps explain WPS115 WPS115 — Require ``snake_case`` for naming class attributes. Attributes in Enum and enum-like classes (Django Choices) are ignored, as they should be written in UPPER_SNAKE_CASE ... .. code:: text $ wps explain 116 WPS116 — Forbid using more than one consecutive underscore in variable names. Reasoning: This is done to gain extra readability. ... .. _configuration: Configuration ============= Before going any further, make sure that you are familiar with ``flake8`` `configuration process `_. By default we encourage everyone to use ``setup.cfg`` to store all the configuration to all ``python`` projects. .. rubric:: Configuring .. automodule:: wemake_python_styleguide.options.config :no-members: .. rubric:: Ignoring violations We know that people might not agree with 100% of our rules. But we still want to provide the best experience for all users. So, you can disable some checks, that you are not ok with. **Note**: you might accidentally break the consistency of this project, when you disable some checks. `Report `_ these cases. There are three ways to ignore some specific violations: 1. Inline ignore with ``# noqa:`` comment and comma separated violation codes 2. Command line argument ``--ignore`` with comma separated violation codes 3. Configuration line inside ``setup.cfg``, `example `_ You can ignore: 1. Whole ``WPS`` letters, this will completely turn off all our custom checks 2. Some specific group (naming, complexity, consistency, best practices, etc) with ``WPS`` and the first number of this group 3. Some specific violation with the full violation code Use `per-file-ignores `_ option, so it is possible to ignore violations on a per-file bases. It means, that you can have different set of violations ignored for different files. Example: .. code:: ini # Inside `setup.cfg`: [flake8] per-file-ignores = # We allow to shadow functions with parameter names, because of the pytest API: tests/*.py: WPS442 .. rubric:: Further reading Read more about `ignoring violations `_ in the official ``flake8`` docs. Formatter ========= Custom formatter for ``flake8`` :term:`violations `. Tries to be beautiful, compact, and informative. Improves the default formatter used by ``flake8``. .. rubric:: Usage To activate this formatter one will need to run: .. code:: bash flake8 --format=wemake your_module.py Or set the configuration option inside ``setup.cfg`` file: .. code:: ini [flake8] format = wemake Option ``format = wemake`` is included into our default configuration. .. image:: https://raw.githubusercontent.com/wemake-services/wemake-python-styleguide/master/docs/_static/running.png To switch back to the default ``flake8`` formatter, you can use ``format = default`` option. There are other formatters out there as well. They can be installed as plugins. .. rubric:: Showing source code You can also (and we recommend to) enable ``--show-source`` option. It can be passed as a command line argument or set in ``setup.cfg``: .. code:: ini [flake8] show-source = True It will change how your reports are formatted, and will show the exact problem with your code: .. code:: » flake8 . --format=wemake --show-source ./wemake_python_styleguide/formatter.py 107:32 E231 missing whitespace after ':' def show_source(self, error:Violation) -> str: ^ It helps to visually identify the problems in your code and fix it faster. We include ``show-source = True`` into our default configuration. .. rubric:: Showing statistic You can also enable ``--statistics`` option. It can be passed as a command line argument or set in ``setup.cfg``: .. code:: ini [flake8] statistics = True It will group all violations by type and tell how many of them do you have and where you have them: .. code:: » flake8 . --format=wemake --show-source --statistics ./wemake_python_styleguide/formatter.py 107:32 E231 missing whitespace after ':' def show_source(self, error:Violation) -> str: ^ ./wemake_python_styleguide/types.py 53:47 E231 missing whitespace after ',' AnyFunctionDefAndLambda = Union[AnyFunctionDef,ast.Lambda] ^ E231: missing whitespace after ':' 1 ./wemake_python_styleguide/formatter.py 1 ./wemake_python_styleguide/types.py Total: 2 All errors: 2 We do not include ``statistics = True`` in our default configuration. It should be only called when user needs to find how many violations there are and what files do contain them. .. rubric:: Showing links to documentation You can also show links to the documentation pages of violations: .. code:: » flake8 . --format=wemake --show-source --show-violation-links ./wemake_python_styleguide/formatter.py 107:32 E231 missing whitespace after ':' -> https://pyflak.es/E231 def show_source(self, error:Violation) -> str: ^ In modern terminals, you can click them to open the respective docs page. We do not include ``show-violation-links`` in our default configuration. .. rubric:: Disabling colors and text highlight Set ``NO_COLOR=1`` environment variable to completely disable all text highlight and colors in ``wemake`` formatter. See https://no-color.org for more information about ``NO_COLOR``. Auto-formatters --------------- List of supported tools. ruff ~~~~ Fully supported. You can run ``ruff check && ruff format`` and there should be no conflicts with ``WPS`` at all. But, ``wemake-python-styleguide`` can and will find additional problems that ``ruff`` missed. isort ~~~~~ We support ``isort``, but we recommend to use ``ruff`` instead. See https://docs.astral.sh/ruff/rules/#isort-i black ~~~~~ Is supported since ``1.0.0``, but we recommend to use ``ruff format`` instead. CI -- This guide shows how to use ``flake8`` inside your ``CI``. travis ~~~~~~ Here's the minimal configuration required to set up ``wemake-python-styleguide``, ``flake8``, ``travis`` up and running: 1. Learn how to `build python projects with travis `_ 2. Copy this configuration into your ``.travis.yml``: .. code:: yaml dist: xenial language: python python: 3.7 install: pip install wemake-python-styleguide script: flake8 . You can also have some inspiration in our own `.travis.yml `_ configuration file. Gitlab CI ~~~~~~~~~ Setting up ``GitlabCI`` is also easy: 1. Learn how `Gitlab CI works `_ 2. Copy this configuration into your ``.gitlab-ci.yml``: .. code:: yaml image: python3.12 test: before_script: pip install wemake-python-styleguide script: flake8 . Examples: - ``GitlabCI`` + ``python`` `official template `_ - ``django`` + ``docker`` + ``GitlabCI`` `template `_ pre-commit ~~~~~~~~~~ To setup `pre-commit `_ with ``wemake-python-styleguide``, add a new hook to the project `.pre-commit-config.yaml` file. For example: .. code:: yaml repos: - repo: https://github.com/wemake-services/wemake-python-styleguide rev: ... # select the last active version hooks: - id: wemake-python-styleguide Docker ------ .. image:: https://img.shields.io/docker/pulls/wemakeservices/wemake-python-styleguide.svg :alt: Dockerhub :target: https://hub.docker.com/r/wemakeservices/wemake-python-styleguide/ .. image:: https://images.microbadger.com/badges/image/wemakeservices/caddy-docker.svg :alt: Image size :target: https://microbadger.com/images/wemakeservices/wemake-python-styleguide We have an existing official image on `DockerHub `_. Usage ~~~~~ You can can use it like so: .. code:: bash docker pull wemakeservices/wemake-python-styleguide docker run --rm wemakeservices/wemake-python-styleguide . Make sure to place proper config file and mount it with the source code like so: .. code:: bash docker run --rm wemakeservices/wemake-python-styleguide -v `pwd`:/code /code You can also use this image with Gitlab CI or any other container-based CIs. Further reading ~~~~~~~~~~~~~~~ - Official `'docker run' docs `_ - Official `GitlabCI docs `_ Editors ------- Note, that some editors might need to disable our own :ref:`formatter ` and set the `default formatter `_ with ``format = default`` in your configuration. - `vscode plugin `_ - `sublime plugin `_ - `atom plugin `_ - `vim plugin `_ - `emacs plugin `_ - :doc:`PyCharm integration ` - `wing plugin `_ Extras ------ There are some tools that are out of scope of this linter, however they are super cool. And should definitely be used! Things we highly recommend to improve your code quality: - `mypy `_ runs type checks on your python code. Finds tons of issues. Makes your code better, improves you as a programmer. You must use, and tell your friends to use it too - `import-linter `_ allows you to define application layers and ensure you do not break that contract. Absolutely must have - `cohesion `_ tool to measure code cohesion, works for most of the times. We recommend to use it as a reporting tool - `dlint `_ tool for encouraging best coding practices and helping ensure Python code is secure - `vulture `_ allows you to find unused code. Has some drawbacks, since there is too many magic in python code. But, it is still very useful tool for the refactoring - `bellybutton `_ allows to write linters for custom use-cases. For example, it allows to forbid calling certain (builtins or custom) functions on a per-project bases. No code required, all configuration is written in ``yaml`` GitHub Actions -------------- .. image:: https://github.com/wemake-services/wemake-python-styleguide/workflows/wps/badge.svg :alt: GitHub Action badge :target: https://github.com/wemake-services/wemake-python-styleguide/actions Good news: we ship pre-built GitHub Action with this project. You can use it from the `GitHub Marketplace `_: .. code:: yaml - name: wemake-python-styleguide uses: wemake-services/wemake-python-styleguide You can also specify any version instead of the ``latest`` tag. Inputs ~~~~~~ .. rubric:: reporter We support three reporting options: - ``terminal`` (default one) when we just dump the output into Action's logs. Is the easiest one to setup, that's why we use it by default - ``github-pr-review`` (recommended) when we use `inline comments `_ inside code reviews - ``github-pr-check`` when we use `GitHub PR Checks `_ for the output - ``github-check`` another way to use `GitHub Checks `_ for the output Take a note that ``github-check``, ``github-pr-review`` and ``github-pr-check`` requires ``GITHUB_TOKEN`` environment variable to be set. Default reporter looks like so: .. image:: https://raw.githubusercontent.com/wemake-services/wemake-python-styleguide/master/docs/_static/terminal.png For example, that's how ``github-pr-reviews`` can be set up: .. code:: yaml - name: wemake-python-styleguide uses: wemake-services/wemake-python-styleguide with: reporter: 'github-pr-review' env: GITHUB_TOKEN: ${{ secrets.github_token }} That's how the result will look like: .. image:: https://raw.githubusercontent.com/wemake-services/wemake-python-styleguide/master/docs/_static/reviewdog.png .. rubric:: path We also support custom ``path`` to be specified: .. code:: yaml - name: wemake-python-styleguide uses: wemake-services/wemake-python-styleguide with: path: './your/custom/path' .. rubric:: cwd We also support custom ``cwd`` to be specified, it will be used to ``cd`` into before any other actions. It can be a custom subfolder with your configuration, etc. .. code:: yaml - name: wemake-python-styleguide uses: wemake-services/wemake-python-styleguide with: cwd: './your/custom/path' .. rubric:: fail_workflow Option which can be set to ``false`` with ``fail_workflow: false`` not to fail the workflow even if violations were found. .. rubric:: filter_mode Can be used to find only new violations and ignore old ones. See https://github.com/reviewdog/reviewdog?tab=readme-ov-file#filter-mode Outputs ~~~~~~~ We also support ``outputs`` from the spec, so you can later pass the output of ``wemake-python-styleguide`` to somewhere else. .. code:: yaml - name: wemake-python-styleguide uses: wemake-services/wemake-python-styleguide - name: Custom Action runs: echo "{{ steps.wemake-python-styleguide.outputs.output }}" Integrations ------------ WPS can integrate with lots of popular and mainstream technologies. In this section you can learn how to use them with WPS. .. rubric:: Featured topics - :doc:`Using WPS with Ruff ` - Integrate WPS into editors and IDEs: - `vscode plugin `_ - `vim plugin `_ - :doc:`PyCharm integration ` - :doc:`Run WPS linting in GitHub Actions pipelines ` .. toctree:: :hidden: plugins.rst editors.rst auto-formatters.rst ondivi.rst docker.rst github-actions.rst ci.rst stubs.rst extras.rst jupyter_notebooks.rst pycharm.rst Plugins and hooks ----------------- We leverage all the existing ``flake8`` `infrastructure `_ and tools. There are different integrations for your workflow. Plugins ~~~~~~~ There are a lot of specific plugins that are not included, because they are, well, specific: - `flake8-pytest-style `_ - `flake8-django `_ - `flake8-scrapy `_ - `pandas-vet `_ - `flake8-SQL `_ - `flake8-annotations `_ - `flake8-logging-format `_ - `flake8-coding `_ - `flake8-spellcheck `_ Hooks ~~~~~ Hooks are 3rd-party apps and services that run ``flake8`` on different occasions: - `pytest-flake8 `_ to run style checks alongside with tests - `pre-commit `_ to run ``flake8`` before all commits locally - Note that since the default ``flake8`` used by ``pre-commit`` does not have ``wemake`` plugin, we have to ask ``pre-commit`` to run local ``flake8`` that is installed via ``wemake``. A sample config for ``.pre-commit-config.yaml``: .. code:: yaml repos: - repo: local hooks: - id: flake8 name: flake8 description: wemake-python-styleguide enforcement entry: flake8 args: ["--config=setup.cfg"] language: python types: [python] - `pronto-flake8 `_ to post inline-comments with violations during code-review inside your CI - Directly modify git pre-commit hook without third party app or service. - Open ``/.git/hooks/pre-commit.sample`` (git runs this script after one calls ``git commit``. If this script exits with code 1, commit would fail) - Add the following code **before** the one checking for whitespace errors. .. code:: bash # Your added code to run wemake-python-styleguide. Add this before # the whitespace error lines flake8 . if [ $? -ne 0 ] then echo "Please fix the ERRORS and commit again." exit 1 fi # If there are whitespace errors, print the offending file names and fail. exec git diff-index --check --cached $against -- - Save and rename the file from ``pre-commit.sample`` to ``pre-commit`` .. _jupyter_notebooks: Jupyter Notebooks ----------------- ``flake8`` does not run on Jupyter Notebooks out-of-the-box. However, there exist projects such as `nbqa `_ and `flake8-nb `_ which allow you to do so. Due to some error/warning codes not applying naturally to Jupyter Notebooks (e.g. "missing module docstring"), it may be a good idea to ignore some of them, for example by running: .. code:: bash $ nbqa flake8 notebook.ipynb --extend-ignore=NIP102,D100,E302,E305,E703,WPS102,WPS114 For example, if we have a file ``notebook.ipynb`` .. image:: https://raw.githubusercontent.com/MarcoGorelli/wemake-python-styleguide/issue-1704/docs/_static/notebook.png we can run this project on this as follows: .. image:: https://raw.githubusercontent.com/MarcoGorelli/wemake-python-styleguide/issue-1704/docs/_static/notebook_terminal.png .. _ondivi: ondivi ------ ``ondivi`` is a Python script filtering coding violations, identified by static analysis, only for changed lines in a Git repo. .. code:: bash pip install ondivi # however we recommend to use `poetry` Then you can integrate ``ondivi`` with your linter. Below is an example of how to use ``ondivi`` with ``flake8``: .. code:: bash flake8 script.py | ondivi Optionally, you can configure ``ondivi`` to filter violations based on a baseline commit or branch, and specify a custom format for parsing linter messages. .. code:: bash flake8 script.py | ondivi --baseline master --format "{filename}:{line_num:d}{other}" Here is a detailed guide on how to set up ``ondivi`` for your project. Baseline Concept ~~~~~~~~~~~~~~~~ When your project is old, you cannot just install and use a new linter because your codebase will contain many violations. Some of them can be auto-formatted, and some of them can be silenced. But, what if there are still too many of them to fix right here and right now? Let me introduce the ``baseline`` concept in ``ondivi``: Specify the ``baseline`` commit or branch which contains your legacy code. Run your linter and pipe its output to ``ondivi``: .. code:: bash flake8 script.py | ondivi --baseline master This will filter out violations present in the specified baseline, allowing you to focus only on new violations. Further Reading ~~~~~~~~~~~~~~~ For more information on ``ondivi`` and advanced usage, please refer to the official repository: `ondivi GitHub repository `_ Support ~~~~~~~ ``flakeheaven`` and ``flakehell`` are not supported because they rely on internal ``flake8`` API, which can lead to compatibility issues as ``flake8`` evolves. In contrast, ``ondivi`` uses only the text output of violations and the state of Git repository, making it more robust and easier to maintain. ``ondivi`` is actively maintained and supported. If you encounter any issues or have questions, please create an issue on the `GitHub repository `_. PyCharm ------- There are three ways to use ``wemake-python-styleguide`` inside `PyCharm `_: 1. `Flake8 Support plugin `_ 2. A custom **File Watcher** configured to run ``flake8`` with WPS enabled 3. An **LSP server** via ``python-lsp-server`` (requires `LSP4IJ `__) The File Watcher approach is useful when you want real-time feedback on every file save or when the plugin does not pick up your WPS installation. The LSP approach provides the richest IDE integration with inline diagnostics, hover tooltips, and quick fixes. Prerequisites ~~~~~~~~~~~~~ Make sure you have ``wemake-python-styleguide`` installed. We recommend using `uv `_: .. code:: bash uv tool install --with-executables-from flake8 wemake-python-styleguide After installation the ``flake8`` binary is available on your ``PATH`` (usually at ``~/.local/bin/flake8`` on Linux and macOS). Setting up a File Watcher ~~~~~~~~~~~~~~~~~~~~~~~~~ 1. Open **Settings** (or **Preferences** on macOS). 2. Navigate to **Tools → File Watchers**. 3. Click **+** and choose ****. 4. Configure the watcher: - **Name**: ``wemake-python-styleguide`` - **File type**: ``Python`` - **Scope**: ``Project Files`` - **Program**: ``flake8`` (or the full path from above) - **Arguments**: ``--select=WPS $FilePath$`` - **Output paths to refresh**: ``$FilePath$`` - **Working directory**: ``$ProjectFileDir$`` 5. In the **Advanced Options** section enable: - **Auto-save edited files to trigger the watcher** - **Trigger the watcher on external changes** 6. Click **OK**. The watcher will run WPS on every save and show violations directly in the PyCharm editor and in the **Inspections** panel. Setting up an LSP server ~~~~~~~~~~~~~~~~~~~~~~~~ This method uses ``python-lsp-server`` together with the LSP4IJ plugin to provide inline error highlighting, hover information, and more. 1. **Install the LSP4IJ plugin** Go to **Settings → Plugins → Marketplace**, search for `LSP4IJ `__ and install it. 2. **Install ``python-lsp-server``** We recommend using `uv `_: .. code:: bash uv tool install \ --with flake8 \ --with wemake-python-styleguide \ --with pyls-flake8 \ python-lsp-server After installation the ``pylsp`` binary is available on your ``PATH`` (usually at ``~/.local/bin/pylsp`` on Linux and macOS). 3. **Find the ``pylsp`` executable** Run ``where pylsp`` (or ``which pylsp``) and note the full path. 4. **Create a new LSP server definition** 1. Open **Settings → Languages & Frameworks → Language Server Protocol → Server Definitions**. 2. Click **+** to add a new server. 3. Set **Name** to ``pylsp-wps`` and **Path** to the ``pylsp`` executable from step 3. 4. Switch to the **Configuration** tab and paste: .. code:: json { "pylsp": { "plugins": { "flake8": { "enabled": true, "select": ["WPS", "E"] }, "pycodestyle": { "enabled": false }, "pyflakes": { "enabled": false }, "mccabe": { "enabled": false } } } } 5. In **Mappings** add ``Python`` as the language for this server. 6. Click **OK**. 5. **Restart PyCharm** Restart the IDE completely so the LSP server can initialise. 6. **Verify** Open a Python file and introduce an intentional WPS violation. You should see inline squiggles and hover tooltips with the violation message. Troubleshooting ~~~~~~~~~~~~~~~ If you do not see any violations: - Make sure the **Program** path points to the ``flake8`` binary that has ``wemake-python-styleguide`` installed inside the same environment. - Try running the same command from the terminal to verify it works. - Check that your project has a valid ``setup.cfg`` or ``pyproject.toml`` with WPS configuration. Stubs ----- If you are using stub ``.pyi`` files and `flake8-pyi `_ extension you might need to ignore several violations that are bundled with this linter. You can still do it on per-file bases as usual. Use ``*.pyi`` glob to list ignored violations: .. code:: ini # Inside `setup.cfg`: [flake8] per-file-ignores = *.pyi: WPS604 You can look at the `returns `_ project as an example. .. _best-practices: Best practices ============== .. plugincodes:: wemake_python_styleguide.violations.best_practices .. _complexity: Complexity ========== .. plugincodes:: wemake_python_styleguide.violations.complexity .. _consistency: Consistency =========== .. plugincodes:: wemake_python_styleguide.violations.consistency Violations ---------- Here we have all violation codes listed for this plugin and its dependencies. Our violation codes are using ``WPS`` letters. Other codes are coming from other tools. .. rubric:: Our own codes ============== ====== Type Codes -------------- ------ System :ref:`WPS000 - WPS099 ` Naming :ref:`WPS100 - WPS199 ` Complexity :ref:`WPS200 - WPS299 ` Consistency :ref:`WPS300 - WPS399 ` Best practices :ref:`WPS400 - WPS499 ` Refactoring :ref:`WPS500 - WPS599 ` OOP :ref:`WPS600 - WPS699 ` ============== ====== .. toctree:: :maxdepth: 0 :caption: Violation types: :hidden: system.rst naming.rst complexity.rst consistency.rst best_practices.rst refactoring.rst oop.rst .. _system: System ====== .. plugincodes:: wemake_python_styleguide.violations.system .. _naming: Naming ====== .. plugincodes:: wemake_python_styleguide.violations.naming .. _refactoring: Refactoring =========== .. plugincodes:: wemake_python_styleguide.violations.refactoring .. _oop: OOP === .. plugincodes:: wemake_python_styleguide.violations.oop Internal Docs ============= Here you can find: 1. How our development process works 2. How to contribute to the project 3. How to write new rules 4. How our internal API looks like This information will also be helpful if you would like to create your own ``flake8`` plugin. How to read this documentation ------------------------------ You will need to start from the :ref:`glossary ` where we define the terms for this project. Then move to the :ref:`contributing ` guide where we specify all technical details about our workflow and tools. Then you will be ready to dive into our :ref:`"Creating a new rule tutorial" `. And finally you will need to go through the API reference to cover specific technical questions you will encounter. Philosophy ---------- 1. Done is better than perfect 2. However, we pursue perfect software 3. False negatives over false positives 4. If you cannot sustain your promise - do not promise 5. Code must be written for people to read, and only incidentally for machines to execute 6. Value consistency over syntax-ish readability 7. Consistent code is more readable than inconsistent 8. Do not force people to choose, they will make mistakes 9. Made choices must be respected Overview -------- This schema should give you a brief overview of what is happening inside our linter. This is a very simplified architecture that will help you to understand how all components are bound together. .. mermaid:: :caption: Architecture overview. sequenceDiagram participant flake8 participant Checker participant Transformation participant Visitor participant Violation flake8->>Checker: flake8 runs our checker alongside with other plugins Checker->>Transformation: Checker asks to perform different ast transformations before we actually start doing anything Checker->>Visitor: Checker runs all visitors that it is aware of Visitor->>Violation: Visitors raise violations when they find bad code Violation-->>flake8: Raised violations are shown to user by flake8 High-level overview of our codebase: .. image:: https://raw.githubusercontent.com/wemake-services/wemake-python-styleguide/master/docs/_static/code-diagram.svg :alt: Code organization We use a `layered architecture `_ that follows this contract: .. literalinclude:: ../.importlinter :language: ini Contributing ------------ .. toctree:: :maxdepth: 2 :caption: This section will help you to know all the tools and terms we are using. glossary.rst contributing.rst debugging.rst Creating a new rule ------------------- .. toctree:: :maxdepth: 2 :caption: This tutorial will guide you through the whole process of creating new rules for this linter. tutorial.rst API Reference ------------- .. toctree:: :maxdepth: 1 :caption: Raw technical information with interface and types declarations, featuring architecture and composition of classes. checker.rst visitors.rst violations.rst transformations.rst types.rst constants.rst formatter.rst .. _glossary: Glossary ======== First of all, we should speak the same language. Here we collect all the specific terms that are used in this project. .. glossary:: rule Some decision that we have made regarding our ``python`` code. Rules can say how we do things or how we do not do things. Each rule is represented with a :term:`violation`. plugin An application developed following `official guides `_ and compatible with ``flake8``. wemake_python_styleguide ``flake8`` :term:`plugin`. Represents a set of :term:`rules ` of how we do write ``python`` code in `wemake.services `_. checker A class compatible with ``flake8`` used as a :term:`plugin` entry point. This class runs all :term:`visitors ` that exist in our application. Technical documentation about the :ref:`checker` is available. formatter A class compatible with ``flake8`` used to show results to users. Each formatter operates with none or multiple :term:`violations `. transformation A way we change existing ``ast`` nodes. We can add properties, fix errors, delete or replace some nodes. Some of the reasons for these actions are: developer experience, simplicity, consistency across different versions, bug-fixing. visitor An object that goes through set of ``ast``, ``tokenize``, or other nodes to find :term:`violation` of our :term:`rules `. Technical documentation about the :ref:`visitors` is available. preset A collection of :term:`visitors `. We use this concept to be able to pass multiple :term:`visitor` classes into the :term:`checker` to be run. violation Stylistic or semantic error that goes against our :term:`rules `. We count each violation definition as a strict rule: how should we behave in different situations. Each violation has its own reasoning, solution, and code examples. Some violations can be configured, some violations contains related constants. Technical documentation about the :ref:`violations` is available. .. _checker: Checker ======= .. automodule:: wemake_python_styleguide.checker :no-members: Constants ========= .. automodule:: wemake_python_styleguide.constants :members: .. _contributing: # How to contribute ## Tutorials If you want to start working on this project, you will need to get familiar with these APIs: - Writing a `flake8` [plugin](http://flake8.pycqa.org/en/latest/plugin-development/) - Using `ast` [module](https://docs.python.org/3/library/ast.html) - [Tokenizer for Python source](https://docs.python.org/3/library/tokenize.html) - [Tokens tutorial](https://www.asmeurer.com/brown-water-python/tokens.html) It is also recommended to take a look at these resources: - Missing `ast` [guide](https://greentreesnakes.readthedocs.io/en/latest/) - List of `python` [static analysis tools](https://github.com/vintasoftware/python-linters-and-code-analysis) - List of `flake8` [extensions](https://github.com/DmytroLitvinov/awesome-flake8-extensions) ## First steps 1. Fork [our repo](https://github.com/wemake-services/wemake-python-styleguide), here's the [guide on forking](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) 2. [Clone your new repo](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository) (forked repo) to have a local copy of the code 3. Apply the required changes! See developer docs on how to work with the code 4. Send a Pull Request to our original repo. Here's [the helpful guide](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request) on how to do that ## Developer's documentation Make sure that you are familiar with [developer's documentation](https://wemake-python-styleguide.rtfd.io/en/latest/pages/api/index.html). That's a main starting point to the future development. You can jump start into the development of new rules by reading ["Creating a new rule tutorial"](https://wemake-python-styleguide.rtfd.io/en/latest/pages/api/tutorial.html). ## Dependencies We use [poetry](https://github.com/sdispater/poetry) to manage the dependencies. To install them you would need to run `install` command: ```bash poetry install ``` To activate your `virtualenv` run `poetry env activate`. ### Adding new flake8 plugins If you are adding a `flake8` plugin dependency (not dev-dependency), you will have to do several things: 1. Install plugin with `poetry` 2. Add docs about the error code to the `pages/usage/violations/index.rst` 3. Add a test that the plugin is working to `tests/test_plugins.py` ## One magic command Run `make test` to run everything we have! ### Building on Windows - Building directly in Windows does not work. - Instead, use a Windows Subsystem for Linux (WSL) such as Ubuntu 18.04 LTS that you can get from the Microsoft Store. - Clone the project to a part of the WSL where Windows does not overwrite permissions, for example _directly to the home of the WSL_ (do `cd` and then `git clone`). That problem looks like [this](https://github.com/wemake-services/wemake-python-styleguide/issues/1007#issuecomment-562719702) and you can read more about why changing the permissions does not work [here](https://github.com/Microsoft/WSL/issues/81). ## Tests We use `pytest` and `flake8` for quality control. We also use `wemake_python_styleguide` itself to develop `wemake_python_styleguide`. To run all tests: ```bash pytest ``` To run linting: ```bash flake8 . ``` These steps are mandatory during the CI. ## Architecture We use [import-linter](https://import-linter.readthedocs.io) to enforce strict layered architecture. ```bash lint-imports ``` See `.importlinter` file for contracts definition. All contracts must be valid for each commit. This step is mandatory during the CI. ## Type checks We use `mypy` to run type checks on our code. To use it: ```bash mypy wemake_python_styleguide ``` This step is mandatory during the CI. ## Spellcheckers This project is developed by a diverse and multilingual group of people. Many of us are not English native speakers and we also know that people can make mistakes and typos even in the simplest of words. So, that's why we use a bunch of tools to find and fix spelling and grammar. You will need to install them manually, because we don't ship them with the dependencies: ```bash pip install codespell flake8-spellcheck ``` And then you can use them: ```bash # codespell: codespell -w wemake_python_styleguide tests docs scripts styles *.md --ignore-words ./tests/whitelist.txt # flake8-spellcheck: flake8 --whitelist ./tests/whitelist.txt . ``` We run them from time to time, this is not in the CI yet. ## Submitting your code We use [trunk based](https://trunkbaseddevelopment.com/) development (we also sometimes call it `wemake-git-flow`). What the point of this method? 1. We use protected `master` branch, so the only way to push your code is via pull request 2. We use issue branches: to implement a new feature or to fix a bug create a new branch named `issue-$TASKNUMBER` 3. Then create a pull request to `master` branch 4. We use `git tag`s to make releases, so we can track what has changed since the latest release So, this way we achieve an easy and scalable development process which frees us from merging hell and long-living branches. In this method, the latest version of the app is always in the `master` branch. ### Before submitting Before submitting your code please do the following steps: 1. Run `pytest` to make sure everything was working before 2. Add any changes you want 3. Add tests for the new changes 4. Add an integration test into `tests/fixtures/noqa.py` 5. Edit documentation if you have changed something significant 6. Update `CHANGELOG.md` with a quick summary of your changes 7. Run `pytest` again to make sure it is still working 8. Run `mypy` to ensure that types are correct 9. Run `flake8` to ensure that style is correct 10. Run `lint-imports` to ensure that architecture contracts are correct You can run everything at once with `make test`, see our `Makefile` for more details. ## Notes for maintainers This section is intended for maintainers only. If you are not a maintainer (or do not know what it means), just skip it. You are not going to miss anything useful. ### Releasing a new version Releasing a new version requires several steps: 1. Ensure that `CHANGELOG.md` is up-to-date and contains all changes 2. Bump version in `pyproject.toml` 3. Bump version in `Dockerfile` that is used for Github Action 4. Run `git commit -a -m 'Version x.y.z release' && git tag -a x.y.x -m 'Version x.y.z' && git push && git push --tags` 5. Run `poetry publish --build` 6. Edit Github Release and mark that new action version is released Done! New version is released. ### Making patches to older versions If you want to release a patch for an older version, that what you have to do: 1. Check out the previous `tag` 2. Create a new branch relative to this tag: `git checkout $TAG_NAME; git checkout -b $RELEASE_NAME` 3. Merge it into master, there might be some `rebase` and `cherry-pick` involved during this operation ## Other help You can contribute by spreading a word about this library. It would also be a huge contribution to write a short article on how you are using this project. You can also share your best practices with us. You can also consider donations to the project: - Number of current supporters: [![Supporters](https://img.shields.io/opencollective/all/wemake-python-styleguide.svg?color=gold&label=supporters)](https://opencollective.com/wemake-python-styleguide) ## List of contributors Here are the awesome people who contributed to our project: [![List of contributors](https://opencollective.com/wemake-python-styleguide/contributors.svg?width=890&button=0)](https://github.com/wemake-services/wemake-python-styleguide/graphs/contributors) :parser: myst_parser.sphinx_ Debugging ========= In case something does not work the way you want there are several ways to debug things. Viewing module contents ----------------------- We recommend to create a simple file with just the part that does not work. We usually call this file ``ex.py`` and remove it before the actual commit. To reveal internals of this Python source code use: * ``python3.12 -m ast ex.py`` * ``python3.12 -m tokenize ex.py`` It might not be enough to find some complex cases, but it helps. Test-driven development ----------------------- A lot of people (including @sobolevn) finds test-driven development really useful to design and debug your code. How? 1. Write a single test that fails for your new feature or exposes a bug 2. Run it with ``pytest tests/full/path/to/your/test_module.py`` 3. Use the magic of ``print`` and ``ast.dump`` to view the contents of nodes 4. Fix the bug or implement a new feature 5. Make sure that everything works now: tests must pass 6. Done! Interactive debugging --------------------- We recommend to use ``ipdb`` for interactive debugging (it is already included as a development package to this project). To start interactive debugging session you will need to: 1. Set ``export PYTHONBREAKPOINT=ipdb.set_trace`` environment variable 2. Put ``breakpoint()`` call in places where you need your debugger to stop 3. Run your program as usual, debugger will stop on places you marked This way allows to view local variables, execute operations step by step, debug complex algorithms. Visual debugging ---------------- One can use ``vscode`` or ``pycharm`` to visually debug your app. In this case you need to setup appropriate entrypoints and run your app in debug mode. .. _formatter: Formatter --------- .. automodule:: wemake_python_styleguide.formatter :no-members: Transformations =============== Transformations are operations that we perform before the initial work is done. There are several types of transformations we do: 1. Enhancing the ``ast`` with new properties and features .. automodule:: wemake_python_styleguide.transformations.ast_tree :members: .. _tutorial: Tutorial ======== When you want to force someone to write the code the way you want: you need to create a :term:`rule` for that. There are multiple options of how this can be done. This guide will walk through all possible cases and cover every decision path. Deciding what exactly to write ------------------------------ The most important thing is the question: what kind of rule do you want to create? Depending on the answer you can end up with either: 1. Creating a new ``flake8`` :term:`plugin` 2. Creating a pair of new :term:`visitor` and :term:`violation` inside this plugin, and some checking logic to find problems with your code 3. Just a new :term:`violation` and checking logic to find problems with your code What does it depend on internally? Writing new plugin ------------------ First of all, you have to decide: 1. Are you writing a separate plugin and adding it as a dependency? 2. Are you writing a built-in extension to this styleguide? How to make a decision? Will this plugin be useful to other developers without this styleguide? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If so, it would be wise to create a separate ``flake8`` plugin. Then you can add newly created plugin as a dependency. Our rules do not make any sense without each other. It is also useful when you try to wrap an existing tool into ``flake8`` API. Real world examples of tools that are useful by them self: - `flake8-eradicate `_ - `flake8-type-annotations `_ Can this plugin be used with the existing checker? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``flake8`` has a very strict API about plugins. Here are some problems that you may encounter: - Some plugins are called once per file, some are called once per line - Plugins should define clear ``violation code`` / ``checker`` relation - It is impossible to use the same letter violation codes for several checkers So, if you want a plugin to work with each logical line - you have to create a custom :term:`plugin`. Real world examples of plugins unsuitable for this checker: - `flake8-broken-line `_ Is this rule out off scope? ~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are awesome tools that cannot be added because they are just simply out of scope. This means that they cover very specific case or technology and not just good-old ``python``. Real world examples of plugins that are out of scope: - `flake8-pytest-style `_ - `flake8-django `_ - `flake8-scrapy `_ All these plugins should be installed individually to the end-user dependencies. And only when user really want it. So, it is up to the user to decide. And these plugins while being awesome won't be added to our project at all. Conclusion ~~~~~~~~~~ If you said "yes" to any of these question - write a :term:`plugin`. Then possibly add it as a dependency to this project. Writing new visitor ------------------- If you are still willing to write a builtin extension to this project, you will have to write a :ref:`violation ` and/or :ref:`visitor `. First of all, you have to decide what base class do you want to use? There are several possibilities: .. autoclasstree:: wemake_python_styleguide.visitors.base When to choose what base class? Imagine that you have several ideas in mind: 1. I want to lint module names not to contain numbers 2. I want to lint code not to contain number ``3`` 3. I want to lint code to disallow multiplication of exactly two number Each of these tasks will require different approaches. 1. Will require to subclass a filename-based visitor 2. Will require to subclass a ``tokenize``-based visitor 3. Will require to subclass a ``ast``-based visitor How to differ these cases by yourself? 1. You need to read though the :ref:`docs ` of ``ast`` and ``tokenize`` modules 2. You can have a look at the existing visitors But, you might not want to write a new visitor. You can reuse existing ones and write only a violation and checking logic. Technical documentation about the :ref:`visitors` is available. Writing new violation --------------------- The only thing you should care about is to select the correct base class for new violation. .. autoclasstree:: wemake_python_styleguide.violations.base It only depends on already selected visitor type, so you won't have to make this decision twice. Technical documentation about the :ref:`violations` is available. Writing business logic ---------------------- When you will have your :term:`visitor` and :term:`violation` it will be required to actually write some logic to raise a ``violation`` from ``visitor``. We do this inside the ``visitor``, but we create protected methods and place logic there. Consider this example: .. code:: python class WrongComprehensionVisitor(BaseNodeVisitor): _max_ifs = 1 def _check_ifs(self, node: ast.comprehension) -> None: if len(node.ifs) > self._max_ifs: # This will restrict to have more than 1 `if` # in your comprehensions: self.add_violation(MultipleIfsInComprehensionViolation(node)) def visit_comprehension(self, node: ast.comprehension) -> None: self._check_ifs(node) self.generic_visit(node) You may also end up using the same logic over and over again. In this case we can decouple it and move to ``logics/`` package. Then it would be easy to reuse something. Writing tests ------------- Writing end-to-end tests ~~~~~~~~~~~~~~~~~~~~~~~~ In end-to-end tests we check that our visitor, violation and business logic work correctly together all the way from flake8 config file to its output. To check all supported violations, a module containing code which raises them: ``noqa.py``. It is for all possible violations. The next thing is test itself which should reside in ``tests/test_checker/test_noqa.py`` module. The main test functions are written already, so probably the only thing to do is to put the violation code into either ``SHOULD_BE_RAISED``. Types ===== .. automodule:: wemake_python_styleguide.types :members: Violations ---------- .. automodule:: wemake_python_styleguide.violations.base :members: Visitors -------- .. automodule:: wemake_python_styleguide.visitors.base :members: # Version history We follow [Semantic Versions](https://semver.org/) since the `0.1.0` release. We used to have incremental versioning before `0.1.0`. Semantic versioning in our case means: - Bugfixes do not bring new features, code that passes on `x.y.0` should pass on `x.y.1`. With the only exception that bugfix can raise old violations in new places, if they were hidden by a buggy behaviour. But we do not add new checks. - Minor releases do bring new features and configuration options. New violations can be added. Code that passes on `x.0.y` might not pass on `x.1.y` release because of the new checks. - Major releases indicate significant milestones or serious breaking changes. There are no major releases right now: we are still at `0.x.y` version. But, in the future we might change the configuration names/logic, change the client facing API, change code conventions significantly, etc. ## 1.8.0 WIP ### Features - Adds `WPS482`: forbid lazy imports, #3639 ## 1.7.1 ### Bugfixes - Fixes `WPS226`. Now the error message includes the quoted string value and usage count, #3745 - Fixes crash on overused `'{0}'` string literal, #3748 ## 1.7.0 ### Features - Extends `WPS365`: match with a single case statement is now also considered simplifiable. Match with simple sequence and mapping patterns are now also considered simplifiable - Extends `WPS349`: Slices with a trailing colon (empty step) like ``array[start:stop:]`` and ``array[start::]`` are now considered as redundant, #1071 - Extends `WPS347`: imports aliased with names from ``--allowed-domain-names`` are now allowed, #3741 ## 1.6.2 ### Bugfixes - Fixes the false positive `WPS222` for nested conditions, #3630 - Fixes the false positive `WPS529` for dict subscripts in the `else` branch, #3501 ## 1.6.1 ### Bugfixes - Fixes false positive `WPS366` allowing the use of a single constant in `or`, #3610 - Fixes the false positive `WPS330` when alternating unary operators, #3594 ## 1.6.0 ### Features - Adds `python3.14` official support - Allows walrus operator in `WPS332`, #3505 - Forbids symmetric bitwise operations in `WPS345`, #3593 - Adds `WPS366`: forbid meaningless boolean operations, #3593 - Forbids complex f-string format specifiers in `WPS237`, #3491 ### Bugfixes - Fixes false positive `WPS457` for ``while True`` loop with ``await`` expressions, #3753 - Fixes the false positive `WPS617` by assigning a function that receives a lambda expression as a parameter, #3597 - Fixes false positive `WPS430` for whitelisted nested functions, #3589 - Fixes false positive `WPS457` for `while True` nested in `try/except`, #3604 ### Removals - **Breaking**: Removes `WPS354`, because it is inconsistent with async code, #3601 ## 1.5.0 ### Features - Adds `WPS481`: for statement not allowed in class and module scopes, #3520 - Allows `/` string in `WPS226`, #3554 - Adds `WPS365`: match statement can be simplified to `if`, #3520 - Allow re-exports in `WPS201`, #3570 ### Bugfixes - Fixes `WPS226` false-positive on fstring parts, #3548 - Fixes false positive `WPS412` with docstring and imports in `__init__.py`, #3569 ### Misc - Improves docs: remove outdated AST online visualisation tool url - Returns `[tool.poetry]` instead of `[project]` in `pyproject.toml` ## 1.4.0 ### Features - Allows `__init__.py` files that consist only of imports, #3486 - Adds `--max-conditions` option, #3493 - Adds `--known-enum-bases` option to support custom enum-like base classes, #3513 ### Misc - Adds custom Sphinx directive `.. plugincodes` for violation rendering, #1318 - Adds violation classes filter for docs rendering, #3490 ## 1.3.0 ### Features - Adds more names to `WPS110`: `spam`, `ham`, `tmp`, `temp`, `arr` ### Bugfixes - Fixes `WPS243` to use number of statements in `finally` body instead of a number of lines, #3458 ## 1.2.0 Due to PEP-695, it's now allowed to use `[]` in decorators only for `python3.12+`. ```python @MyClassDecorator[T, V] def some_function(): ... ``` ### Features - Adds `WPS243`: forbids complex `finally` bodies, #3458 - Adds `WPS478`: forbids using non strict slice operations, #1011 - Adds `WPS479`: forbids using multiline fstrings, #3405 - Adds `WPS480`: forbids using comments inside formatted string, #3404 ### Bugfixes - Removes unnecessary `WPS604` and `WPS614` rules from the `noqa.py`, #3420 - Fixes `WPS115` false-positive on `StrEnum`, `IntEnum`, `IntFlag` attributes, #3381 - Fixes `WPS432`, now it ignores magic numbers in `Literal`, #3397 - Fixes `WPS466` for generic type specifications `MyClassDecorator[T]`, #3417 - Fixes `WPS212` to ignore nested classes and functions when counting `return` statements, #3413 - Improves `WPS349` highlighting, #3437 ## 1.1.0 ### Command line utility This version introduces `wps` CLI tool. `wps explain ` command can be used to access WPS violation docs (same as on website) but without any internet access. ### Features - Adds `WPS476`: forbids to use `await` expressions in `for` loops, #1600 - Adds `WPS477`: forbids `TypeVarTuple` after a `TypeVar` with a default, #3265 ### Bugfixes - Fixes `WPS115` false-positive on `Enum` attributes, #3238 - Removes duplicated `WPS312`, #3239 - Fixes `WPS432`, now it shows literal num, #1402 - Fixes `WPS226`, now it points to the first string literal occurrence, #3267 - Fixes `WPS605` false-positive on `@staticmethod`, #3292 - Fixes `_SELF` name not to trigger `WPS117`, #3310 - Fixes `WPS221` being too strict with f-strings, #3350 ## 1.0.0 ### Ruff This release introduces the new main concept: `ruff` compatibility. Now `WPS` is the only `flake8` plugin that is installed. Other things are done by `ruff`. It is faster, it has autofixing, there are lots of rules. Basically, this way `WPS` just gain lots of new rule and plugins almost for free. It is now stricter than ever! `WPS` now officially supports **ALL** `ruff` existing rules. This means that there are no conflicts between two linters. To run `WPS` and `ruff` together, use: ```bash ruff format && ruff check && flake8 --select=WPS . ``` You can copy our configuration from [`pyproject.toml`](https://github.com/wemake-services/wemake-python-styleguide/blob/bca0a1452335619ee5898e2ab657ca6e4a741f5f/pyproject.toml#L103) (for `ruff`) and [`setup.cfg`](https://github.com/wemake-services/wemake-python-styleguide/blob/bca0a1452335619ee5898e2ab657ca6e4a741f5f/setup.cfg#L7) (for `flake8`). ### Black `WPS` can now also be used with `black` with **default** configuration. However, we recommend using `ruff format` instead. ### Speed `WPS` got a lot faster! Because: - We removed a lot of `flake8` plugins - We removed a lot of rules covered by `ruff` Running `0.19.2` (previous version) on https://github.com/dry-python/returns ```bash » time flake8 . flake8 . 20.63s user 2.47s system 469% cpu 4.919 total ``` The same on `1.0.0`: ``` » time flake8 . flake8 . 8.56s user 0.54s system 898% cpu 1.013 total ``` Which is **2.4x** times faster! ### Integrations We also significantly improved all the integrations! `WPS` can now be used as first-class `pre-commit` hook with: ```yaml repos: - repo: https://github.com/wemake-services/wemake-python-styleguide rev: ... # select the last active version hooks: - id: wemake-python-styleguide ``` Our [GitHub Action](https://github.com/marketplace/actions/wemake-python-styleguide) also got a lot of new options and fixes. ### Removals - **Breaking**: Drops `python3.9` support - **Breaking**: Drops `nitpick` support - **Breaking**: Drops `flake8-commas`, `flake8-isort`, `flake8-debugger`, `flake8-string-format`, `flake8-quotes`, `flake8-comprehensions`, `flake8-bugbear`, `flake8-docstrings`, `flake8-eradicate`, `flake8-bandit`, `flake8-broken-line`, `flake8-rst-docstrings`, `pep8-naming` support, use `ruff format` and `ruff check` instead - **Breaking**: Drops `darglint` support, because it is unmaintained - **Breaking**: Removes `WPS113`, because is covered by `pylint` linter - **Breaking**: Removes `WPS119`, because is covered by `pylint` linter - **Breaking**: Removes `WPS125`, because it is covered by `ruff` linter - **Breaking**: Removes `WPS302`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS304`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS305`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS306`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS309`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS310`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS313`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS315`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS316`, because it is covered by `ruff` linter - **Breaking**: Removes `WPS317`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS318`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS319`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS320`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS323`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS326`, because it is covered by `ruff` linter - **Breaking**: Removes `WPS329`, because it is covered by `ruff` linter - **Breaking**: Removes `WPS331`, because it is covered by `ruff` linter - **Breaking**: Removes `WPS333`, because is covered by `pylint` linter - **Breaking**: Removes `WPS337`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS340`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS341`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS343`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS348`, because it conflicts with `ruff` formatter - **Breaking**: Removes `WPS351`, because it is covered by `ruff` linter - **Breaking**: Removes `WPS352`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS355`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS360`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS361`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS415`, because is covered by `ruff` linter - **Breaking**: Removes `WPS417`, because is covered by `ruff` linter - **Breaking**: Removes `WPS419`, because is covered by `ruff` linter - **Breaking**: Removes `WPS423`, because is covered by `ruff` linter - **Breaking**: Removes `WPS424`, because is covered by `ruff` linter - **Breaking**: Removes `WPS425`, because is covered by `ruff` linter - **Breaking**: Removes `WPS428`, because is covered by `ruff` linter - **Breaking**: Removes `WPS433`, because is covered by `pylint` linter - **Breaking**: Removes `WPS434`, because is covered by `pylint` linter - **Breaking**: Removes `WPS436`, because is covered by `pylint` linter - **Breaking**: Removes `WPS437`, because is covered by `ruff` linter - **Breaking**: Removes `WPS440`, because it was buggy and is covered by `mypy`, #3209 - **Breaking**: Removes `WPS442`, because it was buggy and is covered by `mypy`, #3209 - **Breaking**: Removes `WPS450`, because is covered by `pylint` linter - **Breaking**: Removes `WPS452`, because is covered by `ruff` linter - **Breaking**: Removes `WPS454`, because is covered by `ruff` linter - **Breaking**: Removes `WPS456`, because is covered by `ruff` linter - **Breaking**: Removes `WPS465`, because `|` is now heavily used by typing - **Breaking**: Removes `WPS467`, because is covered by `pylint` linter - **Breaking**: Removes `WPS502`, because is covered by `ruff` linter - **Breaking**: Removes `WPS503`, because is covered by `ruff` linter - **Breaking**: Removes `WPS507`, because is covered by `pylint` linter - **Breaking**: Removes `WPS508`, because is covered by `ruff` linter - **Breaking**: Removes `WPS510`, because is covered by `pylint` linter - **Breaking**: Removes `WPS514`, because is covered by `pylint` linter - **Breaking**: Removes `WPS528`, because is covered by `pylint` linter - **Breaking**: Removes `WPS525`, because is covered by `ruff` linter - **Breaking**: Removes `WPS526`, because is covered by `ruff` linter - **Breaking**: Removes `WPS521`, because is covered by `ruff` linter - **Breaking**: Removes `WPS609`, because is covered by `pylint` linter - **Breaking**: Removes `--i-control-code` setting, if you want to disable some violations, just use `# noqa` or `--ignore` with code that you want to exclude, there's no need to create one more way of disabling some specific violations ### Features - Adds official `python3.13` support - Allows any compares in `assert` statements for `WPS520`, #3112 - Allows walrus operator (`:=`) in comprehesions, #3121 - Allows `pass` in `case` bodies, #2642 - Allows subclassing builtins in `WPS600`, when creating an `Enum`, #2506 - Allows using variables after blocks for `WPS441` in `assert` statements, #2543 - Does not count `self`, `cls`, and `mcs` as arguments for `WPS211` complexity check anymore, #2394 - Allows underscores (`_`) with exactly 3 digits after it in `WPS303`, #3120 - Allows class / instance attribute shadowing in `@dataclass`es for `WPS601`, #1926 - Allows any number of instance attributes on `@dataclass`es in `WPS230`, #2448 - Allows any number of function parameters in `@overload` definitions for `WPS211`, #1957 - Allows using multiline strings when placed on separate lines, #3056 - Allows using `hasattr` builtin function, #2228 - Disallows using `is not` and `not in` as negated conditions in `WPS504`, #2617 - Allows all branches in `if/elif/else` to be negated in `WPS504`, #2617 - Adds a new rule to forbid `lambda` assigns to special attributes, #1733 - Adds a new rule to check problematic function params, #1343 - Adds a new rule to detect duplicate conditions in `if`s and `elif`s, #2241 - Adds a new rule to detect duplicate `case` patterns in `match`, #3206 - Adds a new rule to find too many `match` subjects, #3201 - Adds a new rule to detect too many `case` statements, #3202 - Adds a new rule to find too complex `except` with too many exceptions - Adds a new rule to find too many `PEP695` type params - Adds a new rule to find useless ternary expressions, #1706 - Adds a new rule to forbid `raise SystemExit`, use `sys.exit` instead, #1786 - Adds a new rule to forbid extra syntax in `match ...` subjects, #3217 - Adds new `--allowed-module-metadata` and `--forbidden-module-metadata` configuration options for `WPS410`, #3060 - Now `--allowed-domain-names` also affect `WPS11` to allow custom short variable names, #2554 - Adds support to run `wemake-python-styleguide` as a `pre-commit` hook, #2588 - GitHub Action can now use `cwd:` parameter to specify where your configuration file is, #2474 - GitHub Action can now use `fail_workflow:` parameter to not fail the workflow even if the check did find any issues - GitHub Action can now use `filter_mode:` parameter to specify how ReviewDog will filter found violations, see https://github.com/reviewdog/reviewdog#filter-mode #2239 ### Bugfixes - Fixes `WPS217` to allow simple calls in `f` strings, #3150 - Fixes `WPS217` not to raise on empty `f` strings, because `ruff check` handles that now for us - Fixes `OverusedStringViolation` not to include `'...'` string - Removes `astor` package in favour of `ast.unparse` - Fixes `WPS210` to not count nested local variables in nested scopes #3108 - Fixes `IterableUnpackingViolation` with generic types and `TypeVarTuple` - Fixes `WPS469` detecting incorrect names of raised exceptions, #3109 - Fixes unnormalized paths in formatter output - Fixes `WPS221` to ignore PEP695's `TypeAlias` from line complexity checks - Fixes `WPS474` to only count import collisions in the same context, #2962 - Fixes `WPS612` to count defaults in function definitions, #2478 - Fixes several bugs in `WPS322` with multiline strings detection - Fixes several violations not been detected in `case:` statements - Fixes `WPS314` not detecting `match` statements - Fixes `match` + `case` does not increase cognitive complexity ### Misc - Integration with `ondivi` doc for legacy codebases - Fixes a documentation error for the Formatter (Showing statistic) section - Source code is now formatted with `ruff` - Removes deprecated `ast` nodes from code: `ast.Num`, `ast.Bytes`, `ast.Str`, `ast.NamedConstant`, etc ## 0.19.2 ### Bugfixes - Fixes `WrongEmptyLinesCountViolation` crash on `Callable[..., ...]` #2899 ## 0.19.1 This release fixes how `...` is used. For example, it is common to define function stubs / protocols like this: ```python def some_function(): ... ``` Now, `...` will be excluded from several rules. ### Bugfixes - Fixes `TooDeepNestingViolation` not to trigger on `...` in functions and classes - Fixes `StatementHasNoEffectViolation` not to trigger on `...` in functions and classes, when it is the only node ## 0.19.0 This minor version will be the last release with all the `flake8` plugins. In the future this project will be migrated to be used together with `ruff`. ### Features - Adds official `python3.12` support - **Breaking**: drops `python3.8` support - **Breaking**: Reconsider `object` required base class exception: since `class Klass[_Type]` must not contain `object`, this rule is change to be the opposite: `object` explicit base class must not be used. You can use `ruff` to change all `object`-based types to the new style: `ruff check --select=UP004 --fix .` https://docs.astral.sh/ruff/rules/useless-object-inheritance/ - **Breaking**: allow positional-only parameters, since it is required by `mypy` when using `Concatenate` - Adds support for naming rules for PEP695 type params - Due to how `f`-string are parsed in `python3.12` several token-based violations are not reported anymore for them: `UselessMultilineStringViolation`, `ImplicitRawStringViolation`, `WrongUnicodeEscapeViolation`, `RawStringNotNeededViolation` - `wemake` output formatter now respects `NO_COLOR=1` option to disable text highlighting. See https://no-color.org - Adds `ImportObjectCollisionViolation` to detect the same objects imported under different aliases - Adds `reveal_locals` to the list of forbidden functions - Updates `flake8` to `7.x` ### Bugfixes - Fixes `ForbiddenInlineIgnoreViolation` config parsing. #2590 - Fixes `WrongEmptyLinesCountViolation` for func definitions with ellipsis. #2847 - Fixes `WrongEmptyLinesCountViolation` for multiline implicit string concatenation. #2787 - Fixes `ObjectInBaseClassesListViolation`, `UnpythonicGetterSetterViolation`, `ImplicitInConditionViolation`, `RedundantSubscriptViolation`, `TooLongCompareViolation` to include better error details - Fixes `TooDeepNestingViolation` for `TryStar` and `Match` statements - Fixes `TooLongTryBodyViolation` and `TooManyExceptCasesViolation` to work for `TryStar` statements as well - Fixes `UselessNodeViolation` to work with `TryStar` - Fixes `DuplicateExceptionViolation` to work with `TryStar` - Fixes `TryExceptMultipleReturnPathViolation` to work with `TryStar` - Fixes `IncorrectExceptOrderViolation` to work with `TryStar` - Fixes that `MatchStar` was not checked in pattern matching name assignments - Fixes pattern matching support in `BlockAndLocalOverlapViolation` and `OuterScopeShadowingViolation` ### Misc - Updates multiple`flake8-*` dependencies - Fixes multiple typos in docs ## 0.18.0 ### Features - **Breaking**: drops `python3.7` support, because it has almost reached its EOL - Adds `python3.11` support - Bump `flake8` to version `5.x` - Bump `flake8-*` dependencies to newer versions - Added `ChainedIsViolation` #2443 - Added `BuggySuperContextViolation` #2310 ### Bugfixes - Make `generic_visit()` check script properly handle `with` statements. - Allow calling magic methods with the same name as the enclosing method #2381 - Fix WrongEmptyLinesCountViolation false positive #2531 - Fix OpenWithoutContextManagerViolation false positive #2577 ### Misc - Replaced `flakehell` mentions to `flakeheaven` #2409 ## 0.17.0 ### Features - **Breaking**: drops `python3.6` support - Adds support for pattern matching naming rules, same as other variables - Adds `--show-violation-links` option to show links to violation docs - Adds `__init_subclass__` in the beginning of accepted methods order as per WPS338 #2411 - Adds `WrongEmptyLinesCountViolation` to check for too many lines in functions and methods definitions #2486 ### Bugfixes - Fixes `WPS226` false positives on `|` use in `SomeType | AnotherType` type hints syntax - Now `-1` is not reported to be an overused expression - Allow `__aiter__` to be async iterator - Adds violation method name to error message of `YieldMagicMethodViolation` - Fixes direct docker image invocation #2492 ### Misc - Adds full violation codes to docs and `BaseViolation.full_code` #2409 - Fix documentation mismatch between default setting for `max-string-usages` and enforced rule #2456 - Domain name was changed from `wemake-python-stylegui.de` to `wemake-python-styleguide.rtfd.io` ## 0.16.1 ### Bugfixes - Fixes crash on `'Literal["raise"]'` annotation #2341 - Fixes `WPS471` was not detected on complex assignment targets #2301 - Fixes `flake8-bandit` and `bandit` version conflict #2368 ## 0.16.0 ## Features - Supports new `flake8` version `4.x` - Now `InconsistentYieldViolation` and `InconsistentReturnViolation` are raised when `yield` or `return` is used with `None` where plain version should be used #2151 - Dot `'.'` and comma `','` do not count against string literal overuse limit anymore #2209 - Added `RedundantEnumerateViolation` #1825 - Adds `RaiseFromItselfViolation` #2133 - Adds `ConsecutiveSlicesViolation` #2064 - Adds `KwargsUnpackingInClassDefinitionViolation` #1754 - `DirectMagicAttributeAccessViolation` now only flags instances for which a known alternative exists #2268 - Forbids getting collection element of list by unpacking #1824 - Now `WPS227` forbids returning tuples that are too long #1731 ### Bugfixes - Fixes that `InconsistentComprehensionViolation` was ignoring misaligned `in` expressions #2075 - Fixes some common magic methods not being recognized as such #2281 ### Misc - Removes all `Raises:` from docstrings, they were unused - Added example to `README.md` - Added `why strict is good` - Replaced all `python` with `Python` in `README.md` - Improve Docs: Fixed all typos and grammatical errors in `CHANGELOG.md` - Updated documentation with the recommended `isort` config. #1934 - Updates `typing_extensions` to `4.x` ## 0.15.3 ### Bugfixes - Fixes crash on `python3.10` - Fixes `UselessReturningElseViolation` to not report `else` with `break` #1958 - Fixes `ReassigningVariableToItselfViolation` to not report on `x = (x,)` #1807 - Fixes `ReassigningVariableToItselfViolation` to extract variables from unary operators #1874 - Fixes that `f'{some:,}'` was considered too complex #1921 - Fixes that `range(len(x))` was not allowed even outside `for` loops #1883 - Fixes `UselessReturningElseViolation` to not report `else` with `break` #2187 (even if we have `except` in loop) - Fixes fixture in `UselessReturningElseViolation` #2191 ### Misc - Adds documentation (and tests) for how to run project on Jupyter Notebooks - Updates `mypy` to `0.902` and fixes type issues ## 0.15.2 ### Bugfixes - Fixes `BitwiseAndBooleanMixupViolation` work with PEP 604 union types #1884 - Fixes `CognitiveModuleComplexityViolation` to not trigger for a single-item modules - Fixes that `ConstantConditionViolation` was not reported for a `BoolOp` - Functions and methods marked as `@overload` or `@typing.overload` do not count in complexity rules ### Misc - Updates GitHub Action's base Python image version to `3.8.8` ### Features - Adds a math operations evaluator to improve and allow several violation checks. ## 0.15.1 ### Bugfixes - Fixes `dataclasses` import, it was failing on `python3.6` - Fixes `InconsistentComprehensionViolation` work with `async` comprehensions - Fixes nested comprehensions support for `InconsistentComprehensionViolation` - Fixes multiple `if` support for `InconsistentComprehensionViolation` - Fixes that `NestedTernaryViolation` was not reported for a comprehension - Fixes that `ConstantConditionViolation` was not reported for a comprehension - Fixes that `ConstantConditionViolation` was triggering for `while x := True:` - Fixes that `UselessElseViolation` was not reported for `for`, `while`, and `try` keywords - Fixes false positive `InfiniteWhileLoopViolation` for `try` #1857 - Fixes that `InfiniteWhileLoopViolation` was not triggered on `1` or other truthy nodes ### Misc - Refactors how `tokenize` tests are executed, now we have an option to compile fixture code to make sure it is syntactically valid. ## 0.15.0 aka python3.9 ### Features - Adds `python3.9` support - Forbids to use new-style decorators on `python3.9` - Changes how we treat own/foreign attributes, since now we only check assigned attribute names for `self`/`cls`/`mcs`, but not any other ones. So, now writing `point.x = 1` will not trigger any violations. Previously, it would raise "too short name". - Forbids using non-trivial expressions as an argument to `except` - Forbids using too many variables in a tuple unpacking - Forbids using `float("NaN")`. - Forbids assigning to a slice - Allow `__call__` method to be asynchronous - Allows common strings not to be counted against string constant overuse limit - Forbids to unpack iterable objects to lists #1259 - Forbids to use single `return None` - Add `__await__` to the list of priority magic methods - Forbids to use float zeros (`0.0`) - Forbids `raise Exception` and `raise BaseException` - Forbids to use `%` with zero as the divisor - Forbids testing conditions to just return booleans when it is possible to simply return the condition itself - Forbids to use unsafe infinite loops - Forbids to use raw strings `r''` when not necessary - Forbids to use too complex `f`-strings - Forbids to use too many `raise` statements inside a single function - Forbids to compare with `float` and `complex` values - Forbids single element destruct - Forbids to ignore some violations (configurable) on a line level - Forbids single element unpacking - Forbids to unpack lists with side-effects - Forbids to use multiline strings except for assignments and docstrings - Forbids not returning anything in functions and methods starting with `get_` - Forbids to use empty comment - Forbids using bitwise operation with boolean operation - Forbids inconsistent structuring of multiline comprehensions - Forbids to use unpythonic getters and setters such as `get_attribute` or `set_attribute` - Now `credits`, `license`, and `copyright` builtins are free to shadow ### Bugfixes - Fixes fails of annotation complexity on `Literal[""]` - Fixes how wrong variable names were checked case sensitive with `WPS110` - Fixes false positives DirectMagicAttributeAccessViolation with `__mro__`, `__subclasses__` and `__version__` - Make `WPS326` work when there is comment between string literals - Allowed yield statements in call method - Allow to use `^` with `1` - Fixes false positives in WPS513 and WPS323 - Fixes false positive WPS426 if `lambda` in loop uses only its arguments - Fixes false negative WPS421 with `pprint.pprint` - Fixes WPS441 triggering when reusing variable names in multiple loops - Fixes false positive ImplicitEnumerateViolation on range with step #1742 - Allows to use `_` to declare several unused variables, like: `x, _, _ = coordinates()` - Fixes variable reassignment in class context - Fixes that `*'abc'` was not counted as pointless star expression - Fixes that `-some` was counted as overused expression - Fixes several bugs with attribute names ### Misc - Updates lots of dependencies - Fixed documentation for TooManyPublicAttributesViolation - Updated isort config - Introduce helper script to check for missing calls to `self.generic_visit(node)` in AST visitors - Updates `poetry` version to `1.1` - Updates `reviewdog` version to `0.11.0` and adds `action-depup` ## 0.14.0 aka The Walrus fighter This release was focused on adding `python3.8` support, removing dependencies that can be removed, and fixing bugs. There are breaking changes ahead! We also have this [nice 0.14 migration guide](https://wemake-python-styleguide.rtfd.io/en/latest/pages/changelog/migration_to_0_14.html). ### Features - **Breaking**: removes `flake8-executable`, now using `WPS452` instead of `EXE001..EXE005` - **Breaking**: removes `flake8-print`, now using `WPS421` instead of `T001` - **Breaking**: removes `flake8-builtins`, now using `WPS125` instead of `A001..A005` - **Breaking**: removes `flake8-annotations-complexity`, now using `WPS234` instead of `TAE002` - **Breaking**: removes `flake8-pep3101`, now using `WPS323` instead of `S001`, we also use a new logic for this violation: we check string defs for `%` patterns, and not for `%` operator - **Breaking**: `WPS441` is no longer triggered for `except` blocks, it is now handled by `F821` from `flake8` - **Breaking**: removes `radon`, because `cognitive-complexity` and `mccabe` is enough - **Breaking**: removes `flake8-logging-format` as a direct dependency - **Breaking**: removes `ImplicitTernaryViolation` or `WPS332`, because it has too many false positives #1099 - Removes `flake8-coding`, all encoding strings, visitor and tests for old `WPS323` which is now reused for modulo formatting checks - Adds `python3.8` support - Changes `styleguide.toml` and `flake8.toml` scripts definition - Extracts new violation - `WPS450` from `WPS436` #1118 - Adds domain names options: `--allowed-domain-names` and `--forbidden-domain-names`, that are used to create variable names' blacklist #1106 - Forbids to use `\r` (carriage return) as line breaks in strings #1111 - Forbids to use `:=` operator, it now reuses `WPS332` code - Forbids to use positional only `/` arguments - Forbids to have too many names imported from a single `from ... import` - Forbids to use `continue` and `break` in `finally` - Forbids to use `__reduce__` and `__reduce_ex__` magic methods - Adds `__call__` to list of methods that should be on top #1125 - Allows `_` to be now used as a defined variable - Removes `cognitive_complexity` dependency, now it is built in into our linter - Adds baseline information for all complexity violation messages: `x > baseline` - Changes how cognitive complexity is calculated - Adds support for positional arguments in different checks - Adds `UnreadableNameViolation` as `WPS124` because there are some character combination which is not easy to read - Adds support for `NamedExpr` with in compare type violation - Forbids `float` and `complex` compares ### Bugfixes - Fixes how `i_control_code` behaves with `WPS113` - Fixes that cognitive complexity was ignoring `ast.Continue`, `ast.Break`, and `ast.Raise` statements - Fixes that cognitive complexity was ignoring `ast.AsyncFor` loops - Fixes that annotation complexity was not reported for `async` functions - Fixes that annotation complexity was not reported for lists - Fixes that annotation complexity was not reported for `*` and `/` args - Fixes that annotation complexity was not tested for dot notation attributes - Fixes that annotation complexity fails on string expressions - Fixes bug when `TooManyPublicAttributesViolation` was counting duplicate fields - Fixes negated conditions `WPS504` was not reported for `if` expressions - Fixes that `import dumps` was reported as `WPS347`, now only `from ... import dumps` is checked - Fixes that `from some import a as std` was reported as a vague import with `WPS347` despite having a meaningful alias - Fixes that `WPS501` was reported for `@contextmanager` definition - Fixes `WPS226` to be thrown at nested string type annotations - Fixes `WPS204` reported simplest nodes as overused like `[]` and `call()` - Fixes `WPS204` not reporting overused `f` strings - Fixes `WPS204` reporting overused return type annotations - Fixes `WPS204` reporting `self.` attribute access - Fixes `WPS331` reporting cases that do require some extra steps before return - Fixes `WPS612` not reporting `super()` calls without return - Fixes `WPS404` not raising on wrong `*` and `/` defaults - Fixes `WPS425` raising on `.get`, `getattr`, `setattr`, and other builtin functions without keyword arguments - Fixes `WPS221` reporting differently on different `python` versions - Fixes `WPS221` reporting nested variable annotations - Fixes `WPS509` not reporting nested ternary in grandchildren of `if` - Fixes `WPS509` not reporting nested ternary in ternary - Fixes `WPS426` not reporting nested `lambda` in comprehensions - Fixes several violations to reporting for `ast.Bytes` and `ast.FormattedStr` where `ast.Str` was checked - Fixes `WPS601` reporting shadowing for non-`self` attributes - Fixes `WPS114` not to be so strict - Fixes `WPS122` not raising for `for` and `async for` definitions - Fixes `WPS400` raising for `# type: ignore[override]` comments - Fixes `WPS115` not raising for attributes inside other nodes ### Misc - Changes how tests are executed - Changes how coverage is calculated, adds `coverage-conditional-plugin` - Adds how a violation can be deprecated - Improves old visitor tests with `/` argument cases - Improves old visitor tests with `:=` cases - Adds `local-partial-types` to mypy config - Uses `abc` stdlib's module to mark abstract base classes #1122 - Adds `python3.8` to the CI - Updates a lot of dependencies ## 0.13.4 This is the last `0.13.x` supporting release, we have to concentrate on `python3.8` support and `0.14.0` which will introduce it to the public. ### Bugfixes - Fix false positive ImplicitYieldFromViolation for async functions #1057 - Fixes nested-classes-whitelist option default value for flake8 prior 3.7.8 #1093 - Improve boolean non-keyword arguments validation #1114 ### Misc - Updates `flake8-pep3101` - Updates `flake8-builtins` - Updates `flake8-eradicate` - Several small refactoring sessions - Adds `hypothesis`-based tests - Adds `flakehell` base config - Fixes `flakehell` docs - Fixes `MAX_NOQA_COMMENTS` and related violation docs - Fixes `OverusedExpressionViolation` and `TooManyExpressionsViolation` docs ## 0.13.3 ### Misc - Updates `radon` version - Updates `poetry` version to `1.0` ## 0.13.2 ### Bugfixes - Fixes that Github Action was failing for wrong status code - Fixes `NegatedConditionsViolation` false positive on absent `else` in combination with `elif` - Fixes `WPS528` false positive on augmented assigns - Fixes incorrect message for `WPS349` - Fixes that `reviewdog` was not able to create more than `30` comments per PR ### Misc - `pylint` docs fixed - Fixes docs about implicit `yield` violation ## 0.13.1 ### Bufixes - Fixes that `_` was marked as invalid by `VagueImportViolation` - Fixes that docs for `VagueImportViolation` were misleading - Fixes invalid docs for `BracketBlankLineViolation` #1020 - Add more complex example to `ParametersIndentationViolation` #1021 ### Misc - Now our GitHub Action can be used to leave PR review comments ## 0.13.0 aka The Lintoberfest This is a huge release that was created during the Hactoberfest season. It was impossible without the huge help from [our awesome contributors](https://github.com/wemake-services/wemake-python-styleguide/graphs/contributors?from=2019-06-01&to=2019-11-18&type=c). Thanks a lot to everyone! This release is not focused on any particular area. It features a lot of new rules from different categories. ### Features - Adds cognitive complexity metric, introduced by [`cognitive_complexity`](https://github.com/Melevir/cognitive_complexity) - Adds docstrings linter [`darglint`](https://github.com/terrencepreilly/darglint) - Updates `pep8-naming` and `flake8-comprehensions` - `WPS431` now allow customize whitelist via `nested-classes-whitelist` setting - Forbids to have invalid strings in stared expressions like `**{'@': 1}` - Forbids to use implicit primitive values in a form of `lambda: 0` - Forbids to use approximate math constants - Forbids to redefine string constants - Forbids use of vague import names (e.g. `from json import loads`) - Makes `OveruseOfNoqaCommentViolation` configurable via `--max-noqa-comments` - Forbid incorrectly swapped variables - Forbids to use redundant subscripts (e.g., `[0:7]` or `[3:None]`) - Allows `super()` as a valid overused expression - Forbids to use `super()` with other methods and properties - `WPS350` enforces using augmented assign pattern - Forbids unnecessary literals - `WPS525` forbids comparisons where `in` is compared with single item container - Forbids wrong annotations in assignment - Forbids using multiline `for` and `while` statements - `WPS113` now can be tweaked with `I_CONTROL_CODE` setting - Adds `WPS000` that indicates internal errors - Forbids to use implicit `yield from` - Forbids to start lines with `.` - Enforces better `&`, `|`, `>>`, `<<`, `^` operators usage - Forbids incorrect exception order - Enforces tuples usage with frozenset constructor - Changes how `WPS444` works, now we use stricter logic for `while` and `assert` - Forbids to use `yield from` with incorrect types - Forbids to use consecutive `yield` expressions - Enforces to use `.items()` in loops - Enforces using `.get()` over `key in dict` checks - Forbids to use and declare `float` keys in arrays and dictionaries - Forbids to use `a[len(a) - 1]` because it is just `a[-1]` - Forbids too long call chains like `foo(a)(b)(c)(d)` ### Bugfixes - Fixes `ImplicitElifViolation` false positives on a specific edge cases - Fixes `--i-control-code` setting for `BadMagicModuleFunctionViolation` - Fixes compatibility with flake8 `3.8.x` - Fixes that `not not True` was not detected as `WPS330` - Fixes addition of `MisrefactoredAssignmentViolation` check - Fixes `WrongMagicCommentViolation` not catching certain wrong comments - Fixes `BadMagicModuleFunctionViolation` false positives on class-level methods - Fixes `InconsistentReturnViolation` false positives on nested functions - Fixes that `--i-dont-control-code` was not present in command line options - Fixes `BlockVariableVisitor` false positives on a properties - Fixes that `//` was not recognised as a math operation - Fixes false positive `BlockAndLocalOverlapViolation` on annotations without value assign - Fixes bug when `x and not x` was not detected as the similar conditions by `WPS408` - Fixed that `1.0` and `0.1` were treated as magic numbers ### Misc - Improves Github Action stability - Replace `scripts/tokens.py` and `scripts/parse.py` with external tools - Improves violation code testing - Improves testing of `.. versionchanged` and `previous_codes` properties - Reference `isort` settings requirement for compliance with `WPS318` in docstring - Improves tests: we now ensure that each violation with previous codes also has corresponding versions changed in their documentation ## 0.12.5 ### Bugfixes - We now ignore `@overload` from `BlockAndLocalOverlapViolation` - Now expressions that reuse block variables are not treated as violations, example: `my_var = do_some(my_var)` ### Misc - Adds Github Action and docs how to use it - Adds local Github Action that uses itself for testing - Adds official Docker image and docs about it ## 0.12.4 ### Bugfixes - Fixes bug with `nitpick` colors and new files API - Updates `flake8-docstrings` ## 0.12.3 ### Bugfixes - Fixes that formatting was failing sometimes when colours were not available - Fixes that `1 / number` was not allowed - Fixes that `%` operator was allowed for `0` and `1` ## 0.12.2 ### Features - Adds `reveal_type` to the list of forbidden functions - `WPS517` now allows to use non-string keys inside `**{}`, so this is allowed: `Users.objects.get(**{User.USERNAME_FIELD: username})` ### Bugfixes - Fixes that `{**a, **b}` was reported as duplicate hash items ## 0.12.1 ### Features - Tweaks `nitpick` configuration ### Bugfixes - Changes `radon` and `pydocstyle` versions for better resolution - Fixes `nitpick` urls ### Misc - Improves `README.md` with `flakehell` and `nitpick` mentions - Improves docs all across the project ## 0.12.0 In this release we had a little focus on: 0. Primitives and constants and how to use them 1. Strings and numbers and how to write them 1. OOP features 1. Blocks and code structure, including variable scoping and overlapping variables 1. Overused expressions and new complexity metrics ### Features - **Breaking**: moves `ImplicitInConditionViolation` from `WPS336` to `WPS514` - **Breaking**: now `ExplicitStringConcatViolation` uses `WPS336` - **Breaking**: moves `YieldMagicMethodViolation` from `WPS435` to `WPS611` - Adds `xenon` as a dependency, it also checks for cyclomatic complexity, but uses more advanced algorithm with better results - Forbids to have modules with too many imported names configured by `--max-imported-names` option which is 50 by default - Forbids to raise `StopIteration` inside generators - Forbids to have incorrect method order inside classes - Forbids to make some magic methods async - Forbids to use meaningless zeros in float, binary, octal, hex, and expanentional numbers - Enforces to use `1e10` instead of `1e+10` - Enforces to use big letters for hex numbers: `0xAB` instead of `0xab` - Enforces to use `r'\n'` instead of `'\\n'` - Forbids to have unicode escape characters inside binary strings - Forbids to use `else if` instead of `elif` - Forbids to have too long `try` bodies, basically `try` bodies with more than one statement - Forbids to overlap local and block variables - Forbids to use block variables after the block definitions - Changes how `WrongSlotsViolation` works, now `(...) + value` is restricted in favor of `(..., *value)` - Forbids to have explicit unhashable types in sets and dicts - Forbids to define useless overwritten methods - Enforces `j` prefix over `J` for `complex` numbers - Forbids overused expressions - Forbids explicit `0` division, multiply, pow, addition, and subtraction - Fordids to pow, multiply, or divide by `1` - Forbids to use expressions like `x + -2`, or `y - -1`, or `z -= -1` - Forbids to multiply lists like `[0] * 2` - Forbids to use variable names like `__` and `_____` - Forbids to define unused variables explicitly: `_unused = 2` - Forbids to shadow outer scope variables with local ones - Forbids to have too many `assert` statements in a function - Forbids to have explicit string contact: `'a' + some_data`, use `.format()` - Now `YieldInsideInitViolation` is named `YieldMagicMethodViolation` and it also checks different magic methods in a class - Forbids to use `assert False` and other false-constants - Forbids to use `while False:` and other false-constants - Forbids to use `open()` outside of `with` - Forbids to use `type()` for compares - Forbids to have consecutive expressions with too deep access level - Forbids to have too many public instance attributes - Forbids to use pointless star operations: `print(*[])` - Forbids to use `range(len(some))`, use `enumerate(some)` instead - Forbids to use implicit `sum()` calls and replace them with loops - Forbids to compare with the falsy constants like `if some == []:` ### Bugfixes - Bumps `flake8-eradicate` version and solves `attrs` incompatible versions issue - Bumps `flake8-docstrings` version and solved `pydocstyle` issue - Fixes `TryExceptMultipleReturnPathViolation` not tracking `else` and `finally` returns at the same time - Fixes how `TryExceptMultipleReturnPathViolation` works: now handles `break` and `raise` statements as well - Fixes `WrongLoopIterTypeViolation` not triggering for generator expressions and empty tuples - Fixes `WrongLoopIterTypeViolation` not triggering for numbers (including negative), booleans, `None` - Fixes `WrongLoopIterTypeViolation` position - Fixes `WrongLoopIterTypeViolation` not triggering for compehensions - Fixes `WrongSlotsViolation` not triggering for comprehensions and incorrect `__slots__` names and types - Fixes `WrongSlotsViolation` not triggering for invalid `python` identifiers like `__slots__ = ('123_slot',)` - Fixes `WrongSlotsViolation` triggering for subscripts - Fixes `NestedClassViolation` and `NestedFunctionViolation` not reporting when placed deeply inside other nodes - Fixes when `WrongUnpackingViolation` was not raised for `async for` and `async with` nodes - Fixes when `WrongUnpackingViolation` was not raised for comprehensions - Fixes that `x, y, z = x, z, y` was not recognized as `ReassigningVariableToItselfViolation` - Fixes that `{1, True, 1.0}` was not recognised as a set with duplicates - Fixes that `{(1, 2), (1, 2)}` was not recognised as a set with duplicates - Fixes that `{*(1, 2), *(1, 2)}` was not recognised as a set with duplicates - Fixes that `{1: 1, True: 1}` was not recognised as a dict with duplicates - Fixes that `complex` numbers were always treated like magic, now `1j` is allowed - Fixes that `0.0` was treated as a magic number - Fixes that it was possible to use `_` in module body - Fixes `WrongBaseClassViolation` not triggering for nested nodes like `class Test(call().length):` - Fixes `ComplexDefaultValueViolation` not triggering for nested nodes like `def func(arg=call().attr)` - Fixes `TooShortNameViolation` was not triggering for `_x` and `x_` - Fixes that some magic method were allowed to be generators - Fixes that some magic method were allowed to contain `yield from` - Fixes bug when some correct `noqa:` comments were reported as incorrect - Fixes bug when some `else: return` were not reported as incorrect - Fixes bug when `WPS507` sometimes were raising `ValueError` - Fixes bug when `return None` was not recognized as inconsistent ### Misc - Adds `styles/` directory with style presets for tools we use and recommend - Adds `bellybutton` to the list of other linters - Documents how to use `nitpick` to sync the configuration - Documents how to use `flakehell` to create `baseline`s for legacy integrations - Improves tests for binary, octal, hex, and exponential numbers - Adds new `xenon` CI check - Now handles exceptions in our own code, hope to never see them! - Now uses `coverage` checks in deepsource - Now `@alias` checks that all aliases are valid - Changes how presets are defined - Improves how `DirectMagicAttributeAccessViolation` is tested - Refactors a lot of tests to tests `ast.Starred` - Refactors a lot of tests to have less tests with the same logical coverage - We now use `import-linter` instead of `layer-linter` - Adds docs about CI integration - Now wheels are not universal - Updates docs about `snake_case` in `Enum` fields - Updates docs about `WPS400` and incorrect line number ## 0.11.1 ### Bugfixes - Now using `pygments` as a direct dependency ## 0.11.0 aka The New Violation Codes We had a really big problem: all violations inside `best_practices` was messed up together with no clear structure. We had to fix it before it is too late. So, we broke existing error codes. And now we can promise not to do it ever again. We also have this [nice 0.11 migration guide](https://wemake-python-styleguide.rtfd.io/en/latest/pages/changelog/migration_to_0_11.html) for you to rename your violations with a script. ### Features - **Breaking**: replaces `Z` error code to `WPS` code - **Breaking**: creates new violation group `refactoring.py` - **Breaking**: creates new violation group `oop.py` - **Breaking**: moving a lot of violations from `best_practices` to `refactoring`, `oop`, and `consistency` - Adds new `wemake` formatter (using it now by default) ### Bugfixes - Fixes error message of `OverusedStringViolation` for empty strings - Now does not count string annotations as strings for `OverusedStringViolation` - Fixes `InconsistentReturnVariableViolation` was raised twice ### Misc - Adds migration guide to `0.11` - Improves legacy guide - Adds `--show-source` to the default recommended configuration - Adds better docs about auto-formatters - Adds `autopep8` to CI to make sure that `wps` is compatible with it - Ensures that `--diff` mode works for `flake8` - Renames `Incorrect` to `Wrong` where possible - Renames `IncorrectlyNestedTernaryViolation` to `NestedTernaryViolation` - Renames `IncorrectLoopIterTypeViolation` to `WrongLoopIterTypeViolation` ## 0.10.0 aka The Great Compare This release is mostly targeted at writing better compares and conditions. We introduce a lot of new rules related to this topic improving: consistency, complexity, and general feel from your code. In this release we have ported a lot of existing `pylint` rules, big kudos to the developers of this wonderful tool. ### Features - Adds `flake8-executable` as a dependency - Adds `flake8-rst-docstrings` as a dependency - Validates options that are passed with `flake8` - Forbids to use module level mutable constants - Forbids to over-use strings - Forbids to use `breakpoint` function - Limits yield tuple lengths - Forbids to have too many `await` statements - Forbids to subclass lowercase `builtins` - Forbids to have useless `lambda`s - Forbids to use `len(sized) > 0` and `if len(sized)` style checks - Forbids to use repeatable conditions: `flag or flag` - Forbids to write conditions like `not some > 1` - Forbids to use heterogeneous compares like `x == x > 0` - Forbids to use complex compare with several items (`>= 3`) - Forbids to have class variables that are shadowed by instance variables - Forbids to use ternary expressions inside `if` conditions - Forces to use ternary instead of `... and ... or ...` expression - Forces to use `c < b < a` instead of `a > b and b > c` - Forces to use `c < b < a` instead of `a > b > c` - Forbids to use explicit `in []` and `in ()`, use sets or variables instead - Forces to write `isinstance(some, (A, B))` instead of `isinstance(some, A) or isinstance(some, B)` - Forbids to use `isinstance(some (A,))` - Forces to merge `a == b or a == c` into `a in {b, c}` and to merge `a != b and a != c` into `a not in {b, c}` ### Bugfixes - Fixes incorrect line number for `Z331` - Fixes that `Z311` was not raising for multiple `not in` cases - Fixes a bunch of bugs for rules working with `Assign` and not `AnnAssign` - Fixes that `continue` was not triggering `UselessReturningElseViolation` ### Misc - Renames `logics/` to `logic/` since it is grammatically correct - Renames `Redundant` to `Useless` - Renames `Comparison` to `Compare` - Renames `WrongConditionalViolation` to `ConstantConditionViolation` - Renames `ComplexDefaultValuesViolation` to `ComplexDefaultValueViolation` - Refactors `UselessOperatorsVisitor` - Adds `compat/` package, getting ready for `python3.8` - Adds `Makefile` - A lot of minor dependency updates ## 0.9.1 ### Bugfixes - Fixes issue with `pydocstyle>=4` by glueing its version to `pydocstyle<4` ## 0.9.0 This is mostly a supporting release with several new features and lots of bug fixes. ### Features - Forbids to use magic module methods `__getattr__` and `__dir__` - Forbids to use multiline conditions - Forbids local variables that are only used in `return` statements ### Bugfixes - Fixes module names for modules like `io.py` - Fixes false positive `Z310` for numbers like `0xE` - Fixes false positive for compare ordering with `await` - Fixes problem with missing `_allowed_left_nodes` - Fixes problem false positive for `Z121` when using `_` for unused var names - Fixes false positive for negative number in default values - Fixes error text for `ComplexDefaultValueViolation` - Fixes problem with false positive for `Z459` when a default value is an `Ellipsis` ### Misc - Adds `py.typed` file in case someone will import our code, now it will have types - Adds several missing `@final` decorators - Enforces typing support - Refactors how `typing_extensions` package is used - Adds docs about `black` - Adds big "Star" button - Multiple dependencies update - Better `exclude` rule for `flake8` check - Removed warnings from `pytest` ## 0.8.1 ### Bugfixes - Fixes how `wps_context` is calculated, so `super()` calls are now working ## 0.8.0 ### Features - Updates `flake8` to `3.7+` - Adds `flake8-annotations-complexity` as a dependency, forbids complex annotations - Forbids to use redundant `+`, `~`, `not`, and `-` operators before numbers - Forbids to use complex default values - Forbids to use anything rather than names in `for` loop vars definitions - Forbids to use anything rather than names in `with` block vars definitions - Forbids to use anything rather than names in comprehension vars definitions - Forbids to use direct magic attributes access - Forbids to use negated conditions - Forbids to use too many `# pragma: no cover` comments - Forbids to use nested `try` blocks ### Bugfixes - Fixes problems with empty lines after magic comments, see [#492](https://github.com/wemake-services/wemake-python-styleguide/issues/492) - Fixes error message for `del` keyword: it is now just `'del'` not `'delete'` ### Misc - Removes `flake8-per-file-ignores` plugin, since `flake8` now handles it - Removes `flake8-type-annotations` plugin, since `flake8` now handles it - Improves docs for `WrongKeywordViolation` - Improves docs for `EmptyLineAfterCodingViolation` - Improves docs for `ProtectedAttributeViolation` - Adds docs about `.pyi` files ## 0.7.1 ### Bugfixes - Allows `Generic[SomeType]` to be a valid superclass - Forces to use `flake8` version `3.6` instead of `3.7` ### Misc - Improves docs about using `# type: some` comment in `for` loops ## 0.7.0 ### Features - Now raising a violation for every `bool` non-keyword argument and showing better error message - Changes how `max-arguments` are counted Now `self`, `cls`, and `mcs` count as real arguments - Forbids to use `yield` inside comprehensions - Forbids to have single line triple-quoted string assignments - Forbids to have same items in `set` literals - Forbids to subclass `BaseException` - Forbids to use simplifiable `if` expressions and nodes - Forbids to have incorrect nodes in `class` body - Forbids to have methods without any arguments - Forbids to have incorrect base classes nodes - Enforces consistent `__slots__` syntax - Forbids to use names with trailing `_` without a reason - Forbids to use `super()` with arguments or outside of methods - Forbids to have too many `except` cases - Enforces to have an empty line after `coding` comment - Forbids to use too many `# noqa` comments - Forbids to use variables declared as unused - Forbids to use redundant `else` blocks - Forbids to use inconsistent `return` and `yield` statements - Forbids to use multiple `return` path in `try`/`expect`/`finally` - Forbids to use implicit string concatenation - Forbids to have useless `continue` nodes inside the loops - Forbids to have useless nodes - Forbids to have useless `raise` statements - Adds `params` and `parameters` to black-listed names ### Bugfixes - Fixes a lot of rules that were ignoring `Bytes` node as constant type - Fixes location of the `BooleanPositionalArgumentViolation` - Fixes argument count issue with `async` functions - Fixes `WrongConditionalVisitor` not detecting `tuple` as constants - Fixes `WrongConditionalVisitor` not detecting negative numbers as constants - Fixes some magic number that were not detected based on their location - Fixes error when regular functions named as blacklisted magic methods were forbidden, now we check for methods only - Fixes error when strings like `U'some'` was not triggering unicode violation - Fixes error when string like `U'some'` was not triggering modifier violation ### Misc - Adds `safety` and other dependency checks to the CI process - Improves tests: now `tokenize` works differently inside tests - Improves tests: now testing more brackets cases aka "magic coverage bug" - Improves docs: adds new badge about our code style - Refactoring: trying to use `astor` where possible to simplify the codebase - Refactoring: introduces some new `transformations` - Refactoring: now we do not have any magical text casts for violations - Improves tests: changes how `flake8` is executed, now it is twice as fast - Improves docs: now linting `conf.py` with `flake8` - Improves tests: now we check that ignored violation are raised with `noqa` - Improves docs: we have added a special graph to show our architecture - Improves docs: we now have a clean page for `checker` without extra junk - Improves docs: we now have a tutorial for creating new rules - Refactoring: moves `presets` package to the root - Improves tests: we now lint our layered architecture with `layer-lint` ## Version 0.6.3 ### Bugfixes - Fixes an [issue-450](https://github.com/wemake-services/wemake-python-styleguide/issues/450) with `dict`s with just values and no keys ## Version 0.6.2 ### Bugfixes - Fixes a [crash](https://github.com/wemake-services/wemake-python-styleguide/issues/423) with class attributes assignment ## Version 0.6.1 ### Bugfixes - Fixes a conflict between our plugin and `pyflakes` ## Version 0.6.0 ### Features - Adds `flake8-per-file-ignore` plugin dependency - Adds default values to the `flake8 --help` output - Adds `do` as a restricted variable name - Forbids multiple assignment targets for context managers - Forbids to use incorrect multi-line parameters - Forbids to use `bool` values as positional arguments - Forbids to use extra indentation - Forbids to use inconsistent brackets - Forbids to use multi-line function type annotations - Forbids to use uppercase string modifiers - Forbids to use assign chains: now we only can use one assign per line - Forbids to use assign with unpacking for any nodes except `Name` - Forbids to have duplicate `except` blocks ### Bugfixes - Fixes tests failing on windows (@sobolevn hates windows!), but it still fails sometimes - Fixes bug when `@staticmethod` was treated as a module member - Fixes bug when some nodes were not checked with `TooDeepNestingViolation` - Fixes bug when it was possible to provide non-unique aliases - Fixes incorrect line number for incorrect parameter names - Fixes bug when names like `__some__value__` were not treated as underscored - Fixes bug when assignment to anything rather than name was raising an error ### Misc - Refactoring: now we fix `async` nodes offset in a special transformation - Improves docs: specifies what `transformation` is - Improves docs: making contributing section in the `README` more friendly - Improves build: changes how CI installs `poetry` ## 0.5.1 ### Bugfixes - Fixes all possible errors that happen because of unset `parent` and `function_type` properties ## 0.5.0 ### Features - **Breaking**: removes `--max-conditions` and `--max-elifs` options - **Breaking**: removes `--max-offset-blocks` - **Breaking**: changes default `TooManyConditionsViolation` threshold from `3` to `4` - **Breaking**: changes `TooManyBaseClassesViolation` code from `225` to `215` - Forbids to use `lambda` inside loops - Forbids to use `self`, `cls`, and `mcs` except for first arguments only - Forbids to use too many decorators - Forbids to have unreachable code - Forbids to have statements that have no effect - Forbids to have too long names for modules and variables - Forbids to have names with unicode for modules and variables - Add `variable` to the blacklisted names - Now `RedundantLoopElseViolation` also checks `while` loops ### Bugfixes - Fixes `TooManyConditionsViolation` to work with any conditions, not just `if`s - Fixes `TooManyConditionsViolation` that did not count conditions correctly - Fixes `TooManyForsInComprehensionViolation` to find all comprehension types - Fixes `TooManyElifsViolation` to check module level conditions - Fixes `TooManyBaseClassesViolation` docs location - Fixes `WrongVariableNameViolation` not checking `lambda` argument names - Fixes `OffsetVisitor` incorrect `await` handling ### Misc - Refactoring: moves all complexity checks into `complexity/` folder - Refactoring: improves how different keyword visitors are coupled - Improves docs: we have removed magic comments and code duplication - Improves docs: now `_pages/` is named just `pages/` - Improves docs: now all violations are sorted correctly - Improves tests: now testing different keywords separately - Improves tests: now all violations must be contained in `test_noqa.py` - Improves tests: now we also run `compile()` on all `ast` examples - Improves tests: now we are sure about correct order of violations ## 0.4.0 Development was focused around better test coverage and providing a better API for tests. We also now covering more cases and testing violation texts. ### Features - **Breaking**: removes duplicating module name rules, now we use the same rules for both variables and modules - **Breaking**: removes `--min-module-name-length` options - **Breaking**: renames `--min-variable-name-length` into `--min-name-length` - Dependencies: updates `flake8` version to `3.6` - Dependencies: removes `pycodestyle` pinned version - Restrict unicode names ### Bugfixes - Multiple fixes to error text formats to be more readable - Fixes `UNDERSCORED_NUMBER_PATTERN` to match names like `come_22_me` - Fixes `UpperCaseAttributeViolation` not being displayed in the docs - Fixes consistency checks being duplicated in the docs - Fixes `UnderscoredNumberNameViolation` showing incorrect line number - Fixes `ProtectedAttributeViolation` to respect `super()` and `mcs` - Fixes `ProtectedAttributeViolation` to show correct text - Fixes `BadNumberSuffixViolation` to show correct text - Fixes `TooManyBaseClassesViolation` to show correct text - Fixes `TooManyElifsViolation` to show correct text - Fixes `TooDeepNestingViolation` to show correct text - Fixes `TooManyMethodsViolation` to show correct text - Fixes `ReassigningVariableToItselfViolation` to show correct text - Renames `UnderscoredNumberNameViolation` to `UnderscoredNumberNameViolation` ### Misc - Refactoring: removed duplicate logic inside `logics/filenames.py` - Improves tests: now testing almost all violations inside `noqa.py` - Improves tests: now testing violations text - Improves tests: now all common patterns live in related `conftest.py` - Improves docs: now all configuration options are listed in the violations ## 0.3.0 aka The Hacktoberfest Feast This release was made possible by awesome people who contributed to the project during `#hactoberfest`. List of awesome people: - [@novikovfred](https://github.com/novikovfred) - [@riyasyash](https://github.com/riyasyash) - [@sathwikmatsa](https://github.com/sathwikmatsa) - [@tipabu](https://github.com/tipabu) - [@roxe322](https://github.com/roxe322) - [@geoc0ld](https://github.com/geoc0ld) - [@lensvol](https://github.com/lensvol) - [@SheldonNunes](https://github.com/SheldonNunes) - [@tommbee](https://github.com/tommbee) - [@valignatev](https://github.com/valignatev) - [@vsmaxim](https://github.com/vsmaxim) ### Features - Adds `flake8-print` as a dependency - Adds `typing-extensions` as a dependency - Forbids to use `quit` and `exit` functions - Forbids the comparison of two literals - Forbids the incorrect order comparison, enforcing variable to come first - Forbids underscores before numbers in names - Forbids class level attributes whose name is not in `snake_case` - Forbids comparison of the same variables - Forbids inconsistent octal, binary, and hex numbers - Forbids too many arguments in `lambda` functions - Forbids extra `object` in parent classes list - Forbids `for` loops with unused `else` - Forbids variables self reassignment - Forbids `try` with `finally` without `except` - Forbids `if` statements with invalid conditionals - Forbids opening parenthesis from following keyword without space in between them - Forbids the use of more than 2 `for` loops within a comprehension - Forbids variable names with more than one consecutive underscore - Restricts the maximum number of base classes aka mixins - Forbids importing protected names - Forbids using protected methods and attributes - Forbids `yield` inside `__init__` method ### Bugfixes - Fixes that `MultipleIfsInComprehensionViolation` was not enabled - Fixes flaky behaviour of `test_module_names` test package - Fixed `TooManyMethodsViolation` not displaying line number in output - Fixed `OffsetVisitor` due to python [bug](https://bugs.python.org/issue29205) ### Misc - Updates `poetry` version - Refactoring: some general changes, including better names and APIs - Improves docs: now we have `versionadded` for each violation - Improves docs: now we explicitly state how some violations might be ignored - Improves tests: now we are testing options - Improves tests: now we have different `tests/` folder structure - Improves tests: now we are testing presets - Improves tests: now we are using different logic inside `assert_errors` - Improves tests: now testing magic numbers in more situations - Improves tests: now testing more situations with empty base classes - Improves tests: now testing presets, that they have all the existing visitors - Improves tests: now using stricter `noqa` checks - Improves tests: now testing that any name is allowed when using a variable - Improves types: now all class attributes are marked as `ClassVar` - Improves types: now we use `final` to indicate what should not be changed - Improves types: now we do not have any ugly import hacks ## 0.2.0 aka Revenge of the Async This release was made possible by awesome people who contributed to the project during `#hactoberfest`. List of awesome people: - [@novikovfred](https://github.com/novikovfred) - [@AlwxSin](https://github.com/AlwxSin) - [@TyVik](https://github.com/TyVik) - [@AlexArcPy](https://github.com/AlexArcPy) - [@tommbee](https://github.com/tommbee) ### Features - Now we are counting `async` function as a module member - We now forbid to use `credits()` builtin function - We now check `async for` and `async with` nesting level - We now check `async for` and `async with` variable names - We now count `async` methods as method for classes complexity check - We now count `async` functions as functions for module complexity check - We now check `async` functions names and arguments - We now count `async` functions complexity - We now ignore `async` functions in jones complexity check - We now check for nested `async` functions - We now check for `async` functions with `@staticmethod` decorator ### Misc - Improves docs: add `usage.rst` - Improves docs: adds naming convention to the `naming.py` - Improves docs: multiple typos, bugs, and issues fixes - Improves tests: now we are testing `async` comprehensions ## Version 0.1.0 ### Features - **Breaking**: changes violation codes, now they are grouped by meaning ### Misc - Refactoring: changes how visitors are organized inside the package - Improves docs: now we have a glossary - Refactoring: refactoring terms that violate our glossary - Improves docs: now all error files contain fancy documentation and summary - Improves docs: now we have added API reference to the docs - Improves docs: adds new plugin development guide ## Version 0.0.16 ### Features - Adds `flake8-logging-format` dependency - Adds `flake8-type-annotations` dependency - Adds `flake8-breaking-line` dependency - Removes `flake8-super-call` dependency - Adds `PartialFloatViolation` - Adds `MagicNumberViolation` - Adds `WrongDocCommentViolation` - Adds `MAGIC_NUMBERS_WHITELIST` constant - Changes what variable names are blacklisted, adds `false`, `true`, and `no` ### Misc - Improves docs: now including docs for `--max-condition` option - Improves docs: adds some new `Zen of Python` references - Improves tests: adds many new examples - Improves docs: now each error has its error message displayed in the docs - Improves docs: readme is now ready for the release - Improves docs: now error pages are split - Improves docs: now all `flake8` plugin dependencies are documented ## Version 0.0.15 ### Features - Adds `MultipleIfsInComprehensionViolation` - Adds `TooManyConditionsViolation` - Adds `--max-conditions` option ### Misc - Improves `CONTRIBUTING.md` - Moves issues templates to `.github/` folder - Update error thrown on `RedundantSubscriptViolation` ## Version 0.0.14 ### Features - Adds `WrongModuleNamePatternViolation` and `WrongModuleNameUnderscoresViolation` - Adds `TooManyImportsViolation` error and `--max-imports` option - Adds `--i-control-code` option to ignore `InitModuleHasLogicViolation` - Adds check for underscored numbers - Forbids `u''` strings - Adds `noqa` and `type` comments checks ### Misc - Changes how many errors are generated for limits violations - Refactors how visitors are injected into the checker, now using presets - Creates new visitor type: `BaseTokenVisitor` for working with `tokenize` - Improves typing support - Adds `flake8-bandit` plugin - Adds `flake8-eradicate` plugin - Adds `flake8-print` plugin for development - Removes `delegate` concept from the codebase ## Version 0.0.13 aka The Jones Complexity ### Features - Adds `jones` complexity checker - Adds `--max-line-complexity` and `--max-jones-score` options ### Misc - Improves docs: adds detailed installation instructions - Removes `flake8-blind-except` plugin ## Version 0.0.12 This is just a supporting release. There are no new features introduced. We have **changed** the error codes for general checks. ### Bugfixes - Fixes bug with [nested imports missing `parent`](https://github.com/wemake-services/wemake-python-styleguide/issues/120) - Fixes bug with [incorrect `pycodestyle` version](https://github.com/wemake-services/wemake-python-styleguide/issues/118) - Removes `BareRaiseViolation` as it does not fit the purpose of this package ### Misc - Improves docs: now all errors are sorted by `code` - Improves docs: now all errors have reasoning - Improves docs: some references are now clickable in web version - Improves docs: now docs include `CHANGELOG.md` - Improves docs: now we have templates for `bug` and `rule-request` - Replaced `pytest-isort` with `flake8-isort` ## Version 0.0.11 This is just a supporting release. There are no new features introduced. ### Bugfixes - Fixes [`python3.7` support](https://github.com/wemake-services/wemake-python-styleguide/issues/93) - Fixes [`AttributeError: 'ExceptHandler' object has no attribute 'depth'`](https://github.com/wemake-services/wemake-python-styleguide/issues/112) ### Misc - Introduced the concept of regression testing, see `test/fixtures/regression` - Removed `compat.py` - Fixes some minor typos, problems, markup inside the docs - Adds some new configuration to `sphinx` - Changes `sphinx` docs structure a little bit ## Version 0.0.10 aka The Module Reaper ### Features - Adds `WrongModuleNameViolation`, `WrongModuleMagicNameViolation`, and `TooShortModuleNameViolation` - Adds `--min-module-name-length` config option - Adds a blacklist of module names - Adds `InitModuleHasLogicsViolation` - Adds `EmptyModuleViolation` - Adds a whitelist of magic module names ### Bugfixes - Fixes `Option` class to have have incorrect `type` field, now using strings - Fixes that `WrongStringTokenVisitor` was not activated ### Misc - Improved typing support - Now each error has a link to the corresponding constant (if any) - Improved docs with links to the corresponding configuration flags ## Version 0.0.9 This is just a supporting release. There are no new features introduced. ### Bugfixes - Fixes `Attribute has no 'id'` error - Fixes `missing 'typing_extension'` error ### Misc - Errors are now tested - Complexity tests are refactored ## Version 0.0.8 aka The Complex Complexity ### Features - Now all dependencies are direct, they will be installed together with this package - Adds direct dependencies, now there's no need to install any extra packages - Adds `TooDeepNestingViolation` and `TooManyElifsViolation` checks - Adds `--max-offset-blocks` and `--max-elifs` options - Adds `TooManyModuleMembersViolation` and `TooManyMethodsViolation` checks - Adds `--max-module-members` and `--max-methods` options - Restricts to use `f` strings ### Bugfixes - Removes incorrect `generic_visit()` calls - Removes some unused `getattr()` calls - Refactors how options are registered ### Misc - Improved type support for options parsing ## Version 0.0.7 ### Features - Added new magic methods to the black list - We now do not count `_` as a variable in `TooManyLocals` check - We now restrict to nest `lambda`s - We now allow to configure the minimal variable's name length via `setup.cfg` ### Misc - Refactored how complexity checks are defined - Refactored how errors are defined - Now each check has strict `Raises:` policy which lists all possible errors that this check can find and raise - Changed how visitors are initialized in tests - Tests now cover nested classes' explicit bases - Tests now cover nested classes and functions `noqa` comment ## Version 0.0.6 ### Features - We now check import aliases to be different from the original name - Default complexity checks' values have changed ### Bugfixes - ReadTheDocs build is fixed by providing extra dependencies - Changed how local variables are counted ### Misc - Improved typing support - Added new documentation sections ## Version 0.0.5 ### Features - We now allow `generator_stop` to be a `__future__` import - We now restrict dotted raw imports like: `import os.path` - We now check import aliases as regular variable names ### Misc - We have added a `CONTRIBUTING.md` file to help new contributors ## Version 0.0.4 ### Features - We now check `class`es to match our styleguide - Classes have their own error group `Z3` - Using `@staticmethod` is now forbidden - Declaring `object` as a base class is now required - Now we check that `__del__` magic method is not used - Variable names `async` and `await` are forbidden - We now forbid to use `__future__` imports - We now have a whitelist for `__future__` imports - Imports are now have its own subgroup `Z10` - General rules now start from `Z11` ## Version 0.0.3 ### Features - We now use `Z` as the default code for our errors - We have shuffled errors around, changing code and formats - Now all name errors share the same class - Adds `PrivateNameViolation` - Now imports inside any structures rather than `Module` raises an error - Adds `file` and `klass` as restricted names - Now `__import__` is just a bad function name, not a special case - Now version is defined in `poetry.toml` only - We now have configuration! And it covers all design errors ### Bugfixes - Fixes issue with missing `parent`s :batman: - Fixes issue with `_$NAME` patterns being ignored ## Version 0.0.2 ### Features - Adds some new blacklisted variables' names - Adds docs for each existing error code - Adds whitelisted names for nested functions: `decorator` and `factory` - Adds new blacklisted module's metadata variables - Removed `BAD_IMPORT_FUNCTIONS` variable, now just checking `__import__` ### Testing - Add gen-tests that cover most of the issues - Removed almost all integration tests, saving just a few of them ### Misc - Adds `poetry` as the main project tool - Adds `shpinx` as a documentation tool ## Version 0.0.1 - Initial release :parser: myst_parser.sphinx_ ***************** Source Code Files ***************** This section contains source code files from the project repository. These files are included to provide implementation context and technical details that complement the documentation above. **Files included:** .. code-block:: text naming.py naming.py ========= .. code-block:: python """ Naming is hard! It is, in fact, one of the two hardest problems. These checks are required to make your application easier to read and understand by multiple people over the long period of time. Naming convention ----------------- Our naming convention tries to cover all possible cases. It is partially automated with this linter, but: - Some rules are still WIP - Some rules will never be automated, code reviews to the rescue! General ~~~~~~~ - Use only ``ASCII`` characters for names - Do not use transliteration from any other languages, translate names instead - Use clear names, do not use words that do not mean anything like ``obj`` - Use names of an appropriate length: not too short, not too long - Do not mask builtins - Do not use unreadable character sequences like ``O0`` and ``Il`` - Protected members should use underscore as the first char - Private names with two leading underscores are not allowed - If you need to explicitly state that the variable is unused, prefix it with ``_`` or just use ``_`` as a name - Do not use variables that are stated to be unused, rename them when actually using them - Do not define unused variables unless you are unpacking other values as well - Do not use multiple underscores (``__``) to create unused variables - Whenever you want to name your variable similar to a keyword or builtin, use trailing ``_`` - Do not use consecutive underscores - When writing abbreviations in ``UpperCase`` capitalize all letters: ``HTTPAddress`` - When writing abbreviations in ``snake_case`` use lowercase: ``http_address`` - When writing numbers in ``snake_case`` do not use extra ``_`` before numbers as in ``http2_protocol`` Packages ~~~~~~~~ - Packages must use ``snake_case`` - One word for a package is the most preferable name Modules ~~~~~~~ - Modules must use ``snake_case`` - Module names must not overuse magic names - Module names must be valid Python identifiers Classes ~~~~~~~ - Classes must use ``UpperCase`` - Python's built-in classes, however, are typically lowercase words - Exception classes must end with ``Error`` Instance attributes ~~~~~~~~~~~~~~~~~~~ - Instance attributes must use ``snake_case`` with no exceptions Class attributes ~~~~~~~~~~~~~~~~ - Class attributes must use ``snake_case`` with no exceptions - Enum fields also must use ``snake_case`` Functions and methods ~~~~~~~~~~~~~~~~~~~~~ - Functions and methods must use ``snake_case`` with no exceptions Method and function arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Instance methods must have their first argument named ``self`` - Class methods must have their first argument named ``cls`` - Metaclass methods must have their first argument named ``mcs`` - Python's ``*args`` and ``**kwargs`` should be default names when just passing these values to some other method/function, unless you want to use these values in place, then name them explicitly Global (module level) variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Global variables must use ``CONSTANT_CASE`` - Unless other is required by the API, example: ``urlpatterns`` in Django Variables ~~~~~~~~~ - Variables must use ``snake_case`` with no exceptions - When a variable is unused it must be prefixed with an underscore: ``_user`` Type aliases ~~~~~~~~~~~~ - Must use ``UpperCase`` as real classes - Must not contain word ``type`` in its name Type variables ~~~~~~~~~~~~~~ - Type variables should be named clearly and properly, not just ``T`` or ``_VT`` Pattern matching ~~~~~~~~~~~~~~~~ - All rules from local variables apply - Explicit ``as`` patterns must be used: ``case ... as _var_name`` is not allowed - However, mapping or sequence patterns can contain unused variables: ``case {"a_key": _not_used_value}:`` .. currentmodule:: wemake_python_styleguide.violations.naming """ from typing import final from wemake_python_styleguide.violations.base import ( ASTViolation, MaybeASTViolation, SimpleViolation, ViolationPostfixes, ) @final class WrongModuleNameViolation(SimpleViolation): """ Forbid blacklisted module names. Reasoning: Some module names are not expressive enough. It is hard to tell what you can find inside the ``utils.py`` module. Solution: Rename your module, reorganize the contents. See :py:data:`~wemake_python_styleguide.constants.MODULE_NAMES_BLACKLIST` for the full list of bad module names. Example:: # Correct: github.py views.py # Wrong: utils.py helpers.py See also: https://tonsky.me/blog/utils/ .. versionadded:: 0.1.0 """ error_template = 'Found wrong module name' code = 100 @final class WrongModuleMagicNameViolation(SimpleViolation): """ Forbid magic names (except some whitelisted ones). Reasoning: Do not fall in love with magic. There's no good reason to use magic names when you can use regular names. See :py:data:`~wemake_python_styleguide.constants.MAGIC_MODULE_NAMES_WHITELIST` for the full list of allowed magic module names. Example:: # Correct: __init__.py __main__.py # Wrong: __version__.py .. versionadded:: 0.1.0 """ error_template = 'Found wrong module magic name' code = 101 @final class WrongModuleNamePatternViolation(SimpleViolation): """ Forbid module names that do not match our pattern. Reasoning: Module names must be valid python identifiers. And just like the variable names - module names should be consistent. Ideally, they should follow the same rules. For ``python`` world it is common to use ``snake_case`` notation. We use :py:data:`~wemake_python_styleguide.constants.MODULE_NAME_PATTERN` to validate the module names. Example:: # Correct: __init__.py some_module_name.py test12.py # Wrong: _some.py MyModule.py 0001_migration.py .. versionadded:: 0.1.0 """ error_template = 'Found incorrect module name pattern' code = 102 # General names: @final class WrongVariableNameViolation(ASTViolation): """ Forbid blacklisted variable names. Reasoning: We have found some names that are not expressive enough. However, they appear in the code more than often. All names that we forbid to use could be improved. Solution: Try to use a more specific name instead. If you really want to use any of the names from the list, add a prefix or suffix to it. It will serve you well. Example:: # Correct: html_node_item = None # Wrong: item = None Configuration: This rule is configurable with ``--allowed-domain-names``. Default: :str:`wemake_python_styleguide.options.defaults.ALLOWED_DOMAIN_NAMES` And with ``--forbidden-domain-names``. Default: :str:`wemake_python_styleguide.options.defaults.FORBIDDEN_DOMAIN_NAMES` The options listed above are used to create new variable names' blacklist starting from :py:data:`~wemake_python_styleguide.constants.VARIABLE_NAMES_BLACKLIST`. .. versionadded:: 0.1.0 .. versionchanged:: 1.3.0 Added more names: ``spam``, ``ham``, ``tmp``, ``temp``, ``arr`` """ error_template = 'Found wrong variable name: {0}' code = 110 @final class TooShortNameViolation(MaybeASTViolation): """ Forbid short variable or module names. Reasoning: It is hard to understand what the variable means and why it is used, if its name is too short. Solution: Think of another name. Give more context to it. This rule checks: modules, variables, attributes, functions, methods, and classes. We do not count trailing and leading underscores when calculating length. Example:: # Correct: x_coordinate = 1 abscissa = 2 # Wrong: x = 1 y = 2 Configuration: This rule is configurable with ``--min-name-length``. Default: :str:`wemake_python_styleguide.options.defaults.MIN_NAME_LENGTH` Pass allowed short names with ``--allowed-domain-names``. Default: :str:`wemake_python_styleguide.options.defaults.ALLOWED_DOMAIN_NAMES` .. versionadded:: 0.1.0 .. versionchanged:: 0.4.0 .. versionchanged:: 0.12.0 """ error_template = 'Found too short name: {0}' code = 111 postfix_template = ViolationPostfixes.less_than @final class PrivateNameViolation(MaybeASTViolation): """ Forbid private name pattern. Reasoning: Private is not private in ``python``. So, why should we pretend it is? This might lead to some serious design flaws. Solution: Rename your variable or method to be protected. Think about your design, why do you want to make it private? Are there any other ways to achieve what you want? This rule checks: modules, variables, attributes, functions, and methods. Example:: # Correct: def _collect_coverage(self): ... # Wrong: def __collect_coverage(self): ... .. versionadded:: 0.1.0 .. versionchanged:: 0.4.0 .. versionchanged:: 0.14.0 """ error_template = 'Found private name pattern: {0}' code = 112 @final class SameAliasImportViolation(ASTViolation): """ Forbid using the same alias as the original name in imports. Reasoning: Why would you even do this in the first place? Example:: # Correct: from os import path # Wrong: from os import path as path .. versionadded:: 0.1.0 .. versionchanged:: 0.13.0 .. versionchanged:: 0.14.0 .. versionchanged:: 1.0.0 No longer produced, kept here for historic reasons. This is covered with ``ruff`` and ``pylint`` linters. See ``PLC0414``. """ error_template = 'Found same alias import: {0}' code = 113 disabled_since = '1.0.0' @final class UnderscoredNumberNameViolation(MaybeASTViolation): """ Forbid names with underscored numbers pattern. Reasoning: This is done for consistency in naming. Solution: Do not put an underscore between text and numbers, that is confusing. Rename your variable or modules do not include underscored numbers. This rule checks: modules, variables, attributes, functions, method, and classes. Please, note that putting an underscore that replaces ``-`` in some names between numbers are fine, example: ``ISO-123-456`` would become ``iso123_456``. Example:: # Correct: star_wars_episode2 = 'awesome!' iso123_456 = 'some data' # Wrong: star_wars_episode_2 = 'not so awesome' iso_123_456 = 'some data' .. versionadded:: 0.3.0 .. versionchanged:: 0.4.0 """ error_template = 'Found underscored number name pattern: {0}' code = 114 @final class UpperCaseAttributeViolation(ASTViolation): """ Require ``snake_case`` for naming class attributes. Attributes in Enum and enum-like classes (Django Choices) are ignored, as they should be written in UPPER_SNAKE_CASE Reasoning: Constants with upper-case names belong on a module level. Solution: Move your constants to the module level. Rename your variables so that they conform to ``snake_case`` convention. Configuration: This rule is configurable with ``--known-enum-bases``. Default: :str:`wemake_python_styleguide.options.defaults.KNOWN_ENUM_BASES` Example:: # Correct: MY_MODULE_CONSTANT = 1 class A: my_attribute = 42 # Correct: class Color(enum.Enum): WHITE = 0 LIGHT_GRAY = 1 # Wrong: class A: MY_CONSTANT = 42 .. versionadded:: 0.3.0 """ error_template = 'Found upper-case constant in a class: {0}' code = 115 @final class ConsecutiveUnderscoresInNameViolation(MaybeASTViolation): """ Forbid using more than one consecutive underscore in variable names. Reasoning: This is done to gain extra readability. This naming rule already exists for module names. Example:: # Correct: some_value = 5 __magic__ = 5 # Wrong: some__value = 5 This rule checks: modules, variables, attributes, functions, and methods. .. versionadded:: 0.3.0 .. versionchanged:: 0.4.0 """ error_template = 'Found consecutive underscores name: {0}' code = 116 @final class ReservedArgumentNameViolation(ASTViolation): """ Forbid naming variables ``self``, ``cls``, or ``mcs``. Reasoning: These names are special, they should only be used as first arguments inside methods. Example:: # Correct: class Test: def __init__(self): ... # Wrong: cls = 5 lambda self: self + 12 This rule checks: functions and methods. Having any reserved names in ``lambda`` functions is not allowed. .. versionadded:: 0.5.0 """ error_template = 'Found name reserved for first argument: {0}' code = 117 @final class TooLongNameViolation(MaybeASTViolation): """ Forbid long variable or module names. Reasoning: Too long names are unreadable. It is better to use a shorter alternative. Long names also indicate that this variable is too complex, maybe it may require some documentation. Solution: Think of another name. Give less context to it. This rule checks: modules, variables, attributes, functions, methods, and classes. Example:: # Correct: total_price = 25 average_age = 45 # Wrong: final_price_after_fifteen_percent_sales_tax_and_gratuity = 30 total_age_of_all_participants_in_the_survey_divided_by_twelve = 2 Configuration: This rule is configurable with ``--max-name-length``. Default: :str:`wemake_python_styleguide.options.defaults.MAX_NAME_LENGTH` .. versionadded:: 0.5.0 """ error_template = 'Found too long name: {0}' code = 118 @final class UnicodeNameViolation(MaybeASTViolation): """ Forbid unicode names. Reasoning: This should be forbidden for sanity, readability, and writability. Solution: Rename your entities so that they contain only ASCII symbols. This rule checks: modules, variables, attributes, functions, methods, and classes. Example:: # Correct: some_variable = 'Text with russian: русский язык' # Wrong: переменная = 42 some_變量 = '' .. versionadded:: 0.5.0 .. versionchanged:: 1.0.0 Only produced for filenames now. Code is covered with ``ruff`` and ``pylint`` linter. See ``PLC2401``. """ error_template = 'Found unicode name: {0}' code = 119 @final class TrailingUnderscoreViolation(ASTViolation): """ Forbid trailing ``_`` for names that do not need it. Reasoning: We use trailing underscore for a reason: to indicate that this name shadows a built-in or keyword. So, when overusing this feature for general names: it just harms readability of your program. Solution: Rename your variable not to contain trailing underscores. This rule checks: variables, attributes, functions, methods, and classes. Example:: # Correct: class_ = SomeClass list_ = [] # Wrong: some_variable_ = 1 .. versionadded:: 0.7.0 """ error_template = 'Found regular name with trailing underscore: {0}' code = 120 @final class UnusedVariableIsUsedViolation(ASTViolation): """ Forbid using variables that are marked as unused. We discourage using variables that start with ``_`` only inside functions and methods as local variables. However, we allow to use ``_`` because tools like ``ipython``, ``babel``, and ``django`` enforce it. Reasoning: Sometimes you start to use new logic in your functions, and you start to use variables that once were marked as unused. But, you have not renamed them for some reason. And now you have a lot of confusion: the variable is marked as unused, but you are using it. Why? What's going on? Solution: Rename your variable to be a regular variable without a leading underscore. This way it is declared to be used. Example:: # Correct: def function(): first = 15 return first + 10 # Wrong: def function(): _first = 15 return _first + 10 This rule checks: functions, methods, and ``lambda`` functions. .. versionadded:: 0.7.0 .. versionchanged:: 0.12.0 .. versionchanged:: 0.14.0 """ error_template = 'Found usage of a variable marked as unused: {0}' code = 121 @final class UnusedVariableIsDefinedViolation(ASTViolation): """ Forbid explicit unused variables. Reasoning: While it is ok to define unused variables when you have to, like when unpacking a tuple, it is totally not ok to define explicit unused variables in cases like assignment, function return, exception handling, or context managers. Why do you need this explicitly unused variables? Solution: Remove all unused variables definition. Example:: # Correct: my_function() first, _second = some_tuple() print(first) # Wrong: _ = my_function() _first, _second = some_tuple() This rule checks: assigns, context managers, except clauses. .. versionadded:: 0.12.0 """ error_template = 'Found all unused variables definition: {0}' code = 122 @final class WrongUnusedVariableNameViolation(ASTViolation): """ Forbid unused variables with multiple underscores. Reasoning: We only use ``_`` as a special definition for an unused variable. Other variables are hard to read. It is unclear why would one use it. Solution: Rename unused variables to ``_`` or give it some more context with an explicit name: ``_context``. Example:: # Correct: some_element, _next_element, _ = some_tuple() some_element, _, _ = some_tuple() some_element, _ = some_tuple() # Wrong: some_element, _, __ = some_tuple() .. versionadded:: 0.12.0 """ error_template = 'Found wrong unused variable name: {0}' code = 123 @final class UnreadableNameViolation(MaybeASTViolation): """ Forbid variable or module names which could be difficult to read. Reasoning: Currently one can name your classes like so: ``ZerO0`` Inside it is just ``O`` and ``0``, but we cannot tell it from the word. There are a lot other combinations which are unreadable. Solution: Rename your entity not to contain unreadable sequences. This rule checks: modules, variables, attributes, functions, methods, and classes. See :py:data:`~wemake_python_styleguide.constants.UNREADABLE_CHARACTER_COMBINATIONS` for full list of unreadable combinations. Example:: # Correct: ControlStatement AveragePrice # Wrong: Memo0Output .. versionadded:: 0.14 """ error_template = 'Found unreadable characters combination: {0}' code = 124 @final class BuiltinShadowingViolation(ASTViolation): """ Forbid variable or module names which shadow builtin names. Reasoning: Your code simply breaks Python. After you create ``list = 1``, you cannot not call ``builtin`` function ``list`` and what can be worse than that? Solution: Rename your entity to not shadow Python builtins. Example:: # Correct: my_list = list(some_other) # Wrong: str = '' list = [1, 2, 3] This can also cause problems when defining class attributes, for example:: class A: min = 5 max = min(10, 20) # TypeError: 'int' object is not callable If you feel it is still necessary to use such a class attribute, consider using a `noqa` comment with caution. .. versionadded:: 0.14 .. versionchanged:: 0.15 .. versionchanged:: 1.0.0 No longer produced, kept here for historic reasons. This is covered with ``ruff`` linter. See ``A001``. """ error_template = 'Found builtin shadowing: {0}' code = 125 disabled_since = '1.0.0'