Source code for wemake_python_styleguide.violations.base

# -*- coding: utf-8 -*-

"""
Contains detailed technical information about :term:`violation` internals.

.. _violations:

Violations API
--------------

.. currentmodule:: wemake_python_styleguide.violations.base

.. autoclasstree:: wemake_python_styleguide.violations.base

.. autosummary::
   :nosignatures:

   ASTViolation
   MaybeASTViolation
   TokenizeViolation
   SimpleViolation

Violation can not have more than one base class.
See :ref:`tutorial` for more information about choosing a correct base class.

Conventions
~~~~~~~~~~~

- Each violation class name should end with "Violation"
- Each violation must have a long docstring with full description
- Each violation must have "Reasoning" and "Solution" sections
- Each violation must have "versionadded" policy
- Each violation should have an example with correct and wrong usages
- If violation error template should have a parameter
  it should be the last part of the text: ``: {0}``

Reference
~~~~~~~~~

"""

import ast
import tokenize
from typing import ClassVar, Optional, Set, Tuple, Union

from typing_extensions import final

#: General type for all possible nodes where error happens.
ErrorNode = Union[
    ast.AST,
    tokenize.TokenInfo,
    None,
]


[docs]class BaseViolation(object): """ Abstract base class for all style violations. It basically just defines how to create any error and how to format this error later on. Each subclass must define ``error_template`` and ``code`` fields. Attributes: error_template: message that will be shown to user after formatting. code: violation unique number. Used to identify the violation. previous_codes: just a documentation thing to track changes in time. """ error_template: ClassVar[str] code: ClassVar[int] previous_codes: ClassVar[Set[int]] def __init__(self, node: ErrorNode, text: Optional[str] = None) -> None: """ Creates a new instance of an abstract violation. Arguments: node: violation was raised by this node. If applicable. text: extra text to format the final message. If applicable. """ self._node = node self._text = text
[docs] @final def message(self) -> str: """ Returns error's formatted message with code and reason. Conditionally formats the ``error_template`` if it is required. """ return '{0} {1}'.format( self._full_code(), self.error_template.format(self._text), )
[docs] @final def node_items(self) -> Tuple[int, int, str]: """Returns tuple to match ``flake8`` API format.""" return (*self._location(), self.message())
@final def _full_code(self) -> str: """ Returns fully formatted code. Adds violation letter to the numbers. Also ensures that codes like ``3`` will be represented as ``WPS003``. """ return 'WPS{0}'.format(str(self.code).zfill(3)) def _location(self) -> Tuple[int, int]: """ Return violation location inside the file. Default location is in the so-called "file beginning". """ return 0, 0
class _BaseASTViolation(BaseViolation): """Used as a based type for all ``ast`` violations.""" _node: Optional[ast.AST] @final def _location(self) -> Tuple[int, int]: line_number = getattr(self._node, 'lineno', 0) column_offset = getattr(self._node, 'col_offset', 0) return line_number, column_offset
[docs]class ASTViolation(_BaseASTViolation): """Violation for ``ast`` based style visitors.""" _node: ast.AST
[docs]class MaybeASTViolation(_BaseASTViolation): """ Violation for ``ast`` and modules visitors. Is used for violations that share the same rule for nodes and module names. Is wildly used for naming rules. """ def __init__(self, node=None, text: Optional[str] = None) -> None: """Creates new instance of module violation without explicit node.""" super().__init__(node, text=text)
[docs]class TokenizeViolation(BaseViolation): """Violation for ``tokenize`` based visitors.""" _node: tokenize.TokenInfo @final def _location(self) -> Tuple[int, int]: return self._node.start
[docs]class SimpleViolation(BaseViolation): """Violation for cases where there's no associated nodes.""" _node: None def __init__(self, node=None, text: Optional[str] = None) -> None: """Creates new instance of simple style violation.""" super().__init__(node, text=text)