Skip to content

Commit

Permalink
Refactors getattr calls and improves docs
Browse files Browse the repository at this point in the history
  • Loading branch information
sobolevn committed Jul 28, 2019
1 parent b29c2fd commit ae821dd
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 26 deletions.
2 changes: 1 addition & 1 deletion wemake_python_styleguide/logic/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

def get_exception_name(node: ast.Raise) -> Optional[str]:
"""Returns the exception name or ``None`` if node has not it."""
exception = getattr(node, 'exc', None)
exception = node.exc
if exception is None:
return None

Expand Down
47 changes: 43 additions & 4 deletions wemake_python_styleguide/logic/naming/name_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,32 @@ def get_assigned_name(node: ast.AST) -> Optional[str]:
return node.attr

if isinstance(node, ast.ExceptHandler):
return getattr(node, 'name', None)
return node.name

return None


def flat_variable_names(nodes: Iterable[AnyAssign]) -> Iterable[str]:
"""Returns flat variable names from several nodes."""
"""
Returns flat variable names from several nodes.
Use this function when you need to get list of string variable names
from assign nodes.
Here's an example:
>>> import ast
>>> tree = ast.parse('x: int = 0')
>>> node = tree.body[0]
>>> list(flat_variable_names([node]))
['x']
>>> tree = ast.parse('z = y = 0')
>>> node = tree.body[0]
>>> list(flat_variable_names([node]))
['z', 'y']
"""
return itertools.chain.from_iterable((
get_variables_from_node(target)
for node in nodes
Expand All @@ -43,7 +62,15 @@ def flat_variable_names(nodes: Iterable[AnyAssign]) -> Iterable[str]:


def get_variables_from_node(node: ast.AST) -> List[str]:
"""Gets the assigned names from the list of nodes."""
"""
Gets the assigned names from the list of nodes.
Can be used with any nodes that operate with ``ast.Name`` or ``ast.Tuple``
as targets for the assignment.
Can be used with nodes like ``ast.Assign``, ``ast.Tuple``, ``ast.For``,
``ast.With``, etc.
"""
names: List[str] = []
naive_attempt = extract_name(node)

Expand All @@ -61,7 +88,19 @@ def extract_name(node: ast.AST) -> Optional[str]:
"""
Utility to extract names for several types of nodes.
Should not be used direclty, use safer :py:`~get_assign_names` function.
Is used to get name from node in case it is ``ast.Name``.
Should not be used direclty with assigns,
use safer :py:`~get_assign_names` function.
Example:
>>> import ast
>>> tree = ast.parse('a')
>>> node = tree.body[0].value
>>> extract_name(node)
'a'
"""
if isinstance(node, ast.Starred):
node = node.value
Expand Down
3 changes: 2 additions & 1 deletion wemake_python_styleguide/transformations/ast/enhancements.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import Optional, Tuple, Type

from wemake_python_styleguide.compat.aliases import FunctionNodes
from wemake_python_styleguide.logic.nodes import get_parent
from wemake_python_styleguide.types import ContextNodes


Expand Down Expand Up @@ -86,7 +87,7 @@ def _find_context(
It happened because of the bug #520
See: https://github.com/wemake-services/wemake-python-styleguide/issues/520
"""
parent = getattr(node, 'wps_parent', None)
parent = get_parent(node)
if parent is None:
return None
elif isinstance(parent, contexts):
Expand Down
23 changes: 11 additions & 12 deletions wemake_python_styleguide/visitors/ast/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from wemake_python_styleguide import constants
from wemake_python_styleguide.compat.aliases import FunctionNodes
from wemake_python_styleguide.logic.naming.name_nodes import extract_name
from wemake_python_styleguide.logic.nodes import get_parent
from wemake_python_styleguide.logic.operators import (
count_unary_operator,
Expand All @@ -34,12 +35,11 @@
FormattedStringViolation,
UselessOperatorsViolation,
)
from wemake_python_styleguide.visitors.base import BaseNodeVisitor
from wemake_python_styleguide.visitors.decorators import alias
from wemake_python_styleguide.visitors import base, decorators


@final
class WrongStringVisitor(BaseNodeVisitor):
class WrongStringVisitor(base.BaseNodeVisitor):
"""Restricts several string usages."""

def __init__(self, *args, **kwargs) -> None:
Expand Down Expand Up @@ -93,7 +93,7 @@ def _post_visit(self) -> None:


@final
class MagicNumberVisitor(BaseNodeVisitor):
class MagicNumberVisitor(base.BaseNodeVisitor):
"""Checks magic numbers used in the code."""

_allowed_parents: ClassVar[AnyNodes] = (
Expand Down Expand Up @@ -137,7 +137,7 @@ def _check_is_magic(self, node: ast.Num) -> None:


@final
class UselessOperatorsVisitor(BaseNodeVisitor):
class UselessOperatorsVisitor(base.BaseNodeVisitor):
"""Checks operators used in the code."""

_limits: ClassVar[Mapping[AnyUnaryOp, int]] = {
Expand Down Expand Up @@ -167,15 +167,15 @@ def _check_operator_count(self, node: ast.Num) -> None:


@final
@alias('visit_any_for', (
@decorators.alias('visit_any_for', (
'visit_For',
'visit_AsyncFor',
))
@alias('visit_any_with', (
@decorators.alias('visit_any_with', (
'visit_With',
'visit_AsyncWith',
))
class WrongAssignmentVisitor(BaseNodeVisitor):
class WrongAssignmentVisitor(base.BaseNodeVisitor):
"""Visits all assign nodes."""

def visit_any_with(self, node: AnyWith) -> None:
Expand Down Expand Up @@ -241,14 +241,13 @@ def _check_unpacking_targets(
targets: Iterable[ast.AST],
) -> None:
for target in targets:
if isinstance(target, ast.Starred):
target = target.value # noqa: WPS440
if not isinstance(target, ast.Name):
target_name = extract_name(target)
if target_name is None: # it means, that non name node was used
self.add_violation(WrongUnpackingViolation(node))


@final
class WrongCollectionVisitor(BaseNodeVisitor):
class WrongCollectionVisitor(base.BaseNodeVisitor):
"""Ensures that collection definitions are correct."""

_elements_in_sets: ClassVar[AnyNodes] = (
Expand Down
4 changes: 1 addition & 3 deletions wemake_python_styleguide/visitors/ast/complexity/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,7 @@ def _update_variables(

def _check_sub_node(self, node: AnyFunctionDef, sub_node) -> None:
is_variable = isinstance(sub_node, ast.Name)
context = getattr(sub_node, 'ctx', None)

if is_variable and isinstance(context, ast.Store):
if is_variable and isinstance(sub_node.ctx, ast.Store):
self._update_variables(node, sub_node)
elif isinstance(sub_node, ast.Return):
self.returns[node] += 1
Expand Down
2 changes: 1 addition & 1 deletion wemake_python_styleguide/visitors/ast/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def _check_if_needs_except(self, node: ast.Try) -> None:
self.add_violation(UselessFinallyViolation(node))

def _check_exception_type(self, node: ast.ExceptHandler) -> None:
exception_name = getattr(node, 'type', None)
exception_name = node.type
if exception_name is None:
return

Expand Down
5 changes: 1 addition & 4 deletions wemake_python_styleguide/visitors/ast/naming.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,10 +298,7 @@ def visit_any_assign(self, node: AnyAssign) -> None:
ReassigningVariableToItselfViolation
"""
names = list(itertools.chain.from_iterable((
name_nodes.get_variables_from_node(target)
for target in get_assign_targets(node)
)))
names = list(name_nodes.flat_variable_names([node]))

self._check_reassignment(node, names)
self._check_unique_assignment(node, names)
Expand Down

0 comments on commit ae821dd

Please sign in to comment.