# wemake-python-styleguide [](https://wemake-services.github.io) [](https://opencollective.com/wemake-python-styleguide) [](https://github.com/wemake-services/wemake-python-styleguide/actions/workflows/test.yml) [](https://codecov.io/gh/wemake-services/wemake-python-styleguide) [](https://pypi.org/project/wemake-python-styleguide/) [](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` 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.
``
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:
[](https://opencollective.com/wemake-python-styleguide)
## List of contributors
Here are the awesome people who contributed to our project:
[](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'