Skip to content

Commit

Permalink
Version 0.0.5 release
Browse files Browse the repository at this point in the history
Changes:
1. Now checking aliases' names inside imports, closes #65
2. Adds `generator_stop` to the whitelist of future imports, closes #64
3. Adds `CONTRIBUTING.md`, closes #62
4. Refactors how errors are yielded, closes #61
5. Fixes `wemake.services` badge, closes #59
6. Restricts dotted raw imports, closes #56
  • Loading branch information
sobolevn committed Aug 1, 2018
1 parent 91eced8 commit d676174
Show file tree
Hide file tree
Showing 12 changed files with 304 additions and 8 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

We follow Semantic Versions.

## 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
Expand Down
69 changes: 69 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# How to contribute

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)

It is also recommended to take a look at these resources:

- [Missing `ast` guide](https://greentreesnakes.readthedocs.io/en/latest/)


## Dependencies

We use [`poetry`](https://github.com/sdispater/poetry) to manage the dependencies.

To install them you would need to run two commands:

```bash
poetry install
poetry develop
```

To activate your `virtualenv` run `poetry shell`.


## Tests

We use `pytest` and `flake8` for quality control.
To run all tests:

```bash
pytest
```

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.


## 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. Adds tests for the new changes
4. Edit documentation if you have changed something significant
5. Run `pytest` again to make sure it is still working
6. Run `mypy` to ensure that types are correct


## 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.
What are your best-practices?
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# wemake-python-styleguide

[![wemake.services](https://img.shields.io/badge/style-wemake.services-green.svg?label=&logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC%2FxhBQAAAAFzUkdCAK7OHOkAAAAbUExURQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP%2F%2F%2F5TvxDIAAAAIdFJOUwAjRA8xXANAL%2Bv0SAAAADNJREFUGNNjYCAIOJjRBdBFWMkVQeGzcHAwksJnAPPZGOGAASzPzAEHEGVsLExQwE7YswCb7AFZSF3bbAAAAABJRU5ErkJggg%3D%3D)](http://wemake.services)
[![wemake.services](https://img.shields.io/badge/-wemake.services-green.svg?label=&logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC%2FxhBQAAAAFzUkdCAK7OHOkAAAAbUExURQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP%2F%2F%2F5TvxDIAAAAIdFJOUwAjRA8xXANAL%2Bv0SAAAADNJREFUGNNjYCAIOJjRBdBFWMkVQeGzcHAwksJnAPPZGOGAASzPzAEHEGVsLExQwE7YswCb7AFZSF3bbAAAAABJRU5ErkJggg%3D%3D)](https://wemake.services)
[![Build Status](https://travis-ci.org/wemake-services/wemake-python-styleguide.svg?branch=master)](https://travis-ci.org/wemake-services/wemake-python-styleguide)
[![Coverage](https://coveralls.io/repos/github/wemake-services/wemake-python-styleguide/badge.svg?branch=master)](https://coveralls.io/github/wemake-services/wemake-python-styleguide?branch=master)
[![PyPI version](https://badge.fury.io/py/wemake-python-styleguide.svg)](https://badge.fury.io/py/wemake-python-styleguide)
Expand All @@ -9,6 +9,9 @@

Welcome to the most opinionated linter ever.

`wemake-python-styleguide` is actually just a `flake8` plugin.
The main goal of this tool is to make our `python` code consistent.


## Installation

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "wemake-python-styleguide"
version = "0.0.4"
version = "0.0.5"
description = "Opinionated styleguide that we use in wemake.services"

license = "MIT"
Expand Down
79 changes: 79 additions & 0 deletions tests/test_visitors/test_wrong_import/test_dotted_raw_import.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-

import pytest

from wemake_python_styleguide.visitors.wrong_import import (
DottedRawImportViolation,
WrongImportVisitor,
)

regular_import = """
import {0}
"""

regular_import_with_alias = """
import {0} as alias
"""

from_import = """
from {0} import some
"""

from_import_with_alias = """
from {0} import some as alias
"""


@pytest.mark.parametrize('code', [
regular_import,
regular_import_with_alias,
])
@pytest.mark.parametrize('to_import', [
'dotted.path'
'nested.dotted.path',
])
def test_wrong_dotted_import(assert_errors, parse_ast_tree, code, to_import):
"""Testing that dotted raw imports are restricted."""
tree = parse_ast_tree(code.format(to_import))

visiter = WrongImportVisitor()
visiter.visit(tree)

assert_errors(visiter, [DottedRawImportViolation])


@pytest.mark.parametrize('code', [
regular_import,
regular_import_with_alias,
])
@pytest.mark.parametrize('to_import', [
'os',
'sys',
])
def test_correct_flat_import(assert_errors, parse_ast_tree, code, to_import):
"""Testing that flat raw imports are allowed."""
tree = parse_ast_tree(code.format(to_import))

visiter = WrongImportVisitor()
visiter.visit(tree)

assert_errors(visiter, [])


@pytest.mark.parametrize('code', [
from_import,
from_import_with_alias,
])
@pytest.mark.parametrize('to_import', [
'regular',
'dotted.path'
'nested.dotted.path',
])
def test_regular_from_import(assert_errors, parse_ast_tree, code, to_import):
"""Testing that dotted `from` imports are allowed."""
tree = parse_ast_tree(code.format(to_import))

visiter = WrongImportVisitor()
visiter.visit(tree)

assert_errors(visiter, [])
4 changes: 2 additions & 2 deletions tests/test_visitors/test_wrong_name/test_function_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def test_too_short_function_names(
def test_private_function_names(
assert_errors, parse_ast_tree, code,
):
"""Testing that function can not have too short names."""
"""Testing that function can not have private names."""
tree = parse_ast_tree(code.format('__hidden'))

visiter = WrongNameVisitor()
Expand All @@ -83,7 +83,7 @@ def test_private_function_names(
function_bad_name,
method_bad_name,
])
def test_correct_function_name(
def test_correct_function_names(
assert_errors, parse_ast_tree, correct_name, code,
):
"""Testing that function can have normal names."""
Expand Down
93 changes: 93 additions & 0 deletions tests/test_visitors/test_wrong_name/test_import_alias.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-

import string

import pytest

from wemake_python_styleguide.visitors.wrong_name import (
BAD_VARIABLE_NAMES,
PrivateNameViolation,
TooShortVariableNameViolation,
WrongNameVisitor,
WrongVariableNameViolation,
)

import_alias = """
import os as {0}
"""

from_import_alias = """
from os import path as {0}
"""


@pytest.mark.parametrize('bad_name', BAD_VARIABLE_NAMES)
@pytest.mark.parametrize('code', [
import_alias,
from_import_alias,
])
def test_wrong_import_alias_names(
assert_errors, parse_ast_tree, bad_name, code,
):
"""Testing that import aliases can not have blacklisted names."""
tree = parse_ast_tree(code.format(bad_name))

visiter = WrongNameVisitor()
visiter.visit(tree)

assert_errors(visiter, [WrongVariableNameViolation])


@pytest.mark.parametrize('short_name', string.ascii_letters)
@pytest.mark.parametrize('code', [
import_alias,
from_import_alias,
])
def test_too_short_import_alias_names(
assert_errors, parse_ast_tree, short_name, code,
):
"""Testing that import aliases can not have too short names."""
tree = parse_ast_tree(code.format(short_name))

visiter = WrongNameVisitor()
visiter.visit(tree)

assert_errors(visiter, [TooShortVariableNameViolation])


@pytest.mark.parametrize('code', [
import_alias,
from_import_alias,
])
def test_private_import_alias_names(
assert_errors, parse_ast_tree, code,
):
"""Testing that import aliases can not have too private names."""
tree = parse_ast_tree(code.format('__hidden'))

visiter = WrongNameVisitor()
visiter.visit(tree)

assert_errors(visiter, [PrivateNameViolation])


@pytest.mark.parametrize('correct_name', [
'my_alias',
'xy',
'test',
'_protected',
])
@pytest.mark.parametrize('code', [
import_alias,
from_import_alias,
])
def test_correct_import_alias_names(
assert_errors, parse_ast_tree, correct_name, code,
):
"""Testing that import aliases can have normal names."""
tree = parse_ast_tree(code.format(correct_name))

visiter = WrongNameVisitor()
visiter.visit(tree)

assert_errors(visiter, [])
3 changes: 1 addition & 2 deletions wemake_python_styleguide/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,4 @@ def run(self) -> Generator[CheckResult, None, None]:
visiter.visit(self.tree)

for error in visiter.errors:
lineno, col_offset, message = error.node_items()
yield lineno, col_offset, message, type(self)
yield (*error.node_items(), type(self))
1 change: 1 addition & 0 deletions wemake_python_styleguide/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,5 @@
#: List of allowed ``__future__`` imports.
FUTURE_IMPORTS_WHITELIST = frozenset((
'annotations',
'generator_stop',
))
21 changes: 21 additions & 0 deletions wemake_python_styleguide/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,27 @@ class FutureImportViolation(BaseStyleViolation):
_code = 'Z102'


class DottedRawImportViolation(BaseStyleViolation):
"""
This rule forbids to use imports like ``import os.path``.
Example::
# Correct:
from os import path
# Wrong:
import os.path
Note:
Returns Z103 as error code
"""

_error_tmpl = '{0} Found dotted raw import "{1}"'
_code = 'Z103'


class WrongKeywordViolation(BaseStyleViolation):
"""
This rule forbids to use some keywords from ``python``.
Expand Down
11 changes: 9 additions & 2 deletions wemake_python_styleguide/visitors/wrong_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from wemake_python_styleguide.constants import FUTURE_IMPORTS_WHITELIST
from wemake_python_styleguide.errors import (
DottedRawImportViolation,
FutureImportViolation,
LocalFolderImportViolation,
NestedImportViolation,
Expand Down Expand Up @@ -42,13 +43,19 @@ def _check_future_import(self, node: ast.ImportFrom):
FutureImportViolation(node, text=alias.name),
)

def _check_dotted_raw_import(self, node: ast.Import):
for alias in node.names:
if '.' in alias.name:
self.add_error(DottedRawImportViolation(node, text=alias.name))

def visit_Import(self, node: ast.Import):
"""Used to find nested `import` statements."""
"""Used to find wrong `import` statements."""
self._check_nested_import(node)
self._check_dotted_raw_import(node)
self.generic_visit(node)

def visit_ImportFrom(self, node: ast.ImportFrom):
"""Used to find nested `from import` statements and local imports."""
"""Used to find wrong `from import` statements."""
self._check_local_import(node)
self._check_nested_import(node)
self._check_future_import(node)
Expand Down
Loading

0 comments on commit d676174

Please sign in to comment.