GithubHelp home page GithubHelp logo

wemake-services / wemake-python-styleguide Goto Github PK

View Code? Open in Web Editor NEW
2.4K 30.0 381.0 10.25 MB

The strictest and most opinionated python linter ever!

Home Page: https://wemake-python-styleguide.rtfd.io

License: MIT License

Python 99.78% Makefile 0.03% Dockerfile 0.09% Shell 0.10%
python python3 flake8 flake8-plugin styleguide wemake-services code-quality linter wemake hacktoberfest

wemake-python-styleguide's Introduction

wemake-python-styleguide

wemake.services Supporters Build Status codecov Python Version wemake-python-styleguide


Welcome to the strictest and most opinionated Python linter ever.

wemake-python-styleguide logo

wemake-python-styleguide is actually a flake8 plugin with some other plugins as dependencies.

Quickstart

pip install wemake-python-styleguide

You will also need to create a setup.cfg file with the configuration.

Try it online!

We highly recommend to also use:

  • flakeheaven for easy integration into a legacy codebase
  • nitpick for sharing and validating configuration across multiple projects

Running

flake8 your_module.py

This app is still just good old flake8! And it won't change your existing workflow.

invocation results

See "Usage" section in the docs for examples and integrations.

We also support GitHub Actions as first class-citizens. Try it out!

Strict is the new cool

Strict linting offers the following benefits to developers and companies:

  1. Ensures consistency - no matter who works on it, the end product will always be the same dependable code
  2. Helps avoid potential bugs - strict rules make sure that you don't make common mistakes
  3. Efficient code reviews - each piece of code has a similar familiar style and syntax. If it passes all the checks, there's little left to review!
  4. Fewer code revisions - strict linting ensures that you don't have to re-write the codebase again and again
  5. Reduce code redundancy - Sometimes we write complex code as we are thinking in a certain way about a problem. The linter offers suggestions that can help simplify the code and eliminate redundant statements

What we are about

The ultimate goal of this project is to make all people write exactly the same Python code.

flake8 pylint black mypy wemake-python-styleguide
Formats code?
Finds style issues? 🤔 🤔
Finds bugs? 🤔
Finds complex code? 🤔
Has a lot of strict rules? 🤔
Has a lot of plugins? 🤔

We have several primary objectives:

  1. Significantly reduce the complexity of your code and make it more maintainable
  2. Enforce "There should be one -- and preferably only one -- obvious way to do it" rule to coding and naming styles
  3. Protect developers from possible errors and enforce best practices

You can find all error codes and plugins in the docs.

What we are not

We are not planning to do the following things:

  1. Assume or check types, use mypy together with our linter
  2. Reformat code, since we believe that developers should do that
  3. Check for SyntaxError or logical bugs, write tests instead
  4. Appeal to everyone. But, you can switch off any rules that you don't like

Supporting us 🎉

We in wemake.services make all our tools open-source by default, so the community can benefit from them. If you use our tools and they make your life easier and brings business value, you can return us a favor by supporting the work we do.

Gold Tier

Silver Tier

Bronze Tier

Show your style 😎

If you use our linter - it means that your code is awesome. You can be proud of it! And you should share your accomplishment with others by including a badge in your README file. It looks like this:

wemake-python-styleguide

Markdown

[![wemake-python-styleguide](https://img.shields.io/badge/style-wemake-000000.svg)](https://github.com/wemake-services/wemake-python-styleguide)

Restructured text

.. image:: https://img.shields.io/badge/style-wemake-000000.svg
   :target: https://github.com/wemake-services/wemake-python-styleguide

Contributing

We warmly welcome all contributions!

List of contributors

See "Contributing" section in the documentation if you want to contribute.

You can start with issues that need some help right now.

wemake-python-styleguide's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wemake-python-styleguide's Issues

Forbid `staticmethod`s

In my opinion staticmethod should not be used.

It is better to use regular methods or regular functions.
There should be nothing in between.

Disallow global file ignores with `flake8: noqa`

I don't like the idea that some files are excluded from linting.
But, I believe that this might be useful for several cases.

But, we need to do it inside the configuration file, not in a separate file.

Why?
Because it is hard to tell which files are ignored, and which files are not.
In configuration it is pretty visible from the very first sight.

Related #53

Forbid `# type:` comments

We should use annotations to provide types.
The only type comment that is allowed is: # type: ignore

Rules

Rules to check and implement:

General

  • no nested functions
  • no nested classes (Meta as whitelist)
  • no unused arguments
  • no len(x) == 0 in if conditions
  • no always True checks
  • no raise (without new exception) not within except
  • no raise NotImplemented
  • no __author__
  • no / linebrakes

Complexity

  • too many local variables
  • too many arguments
  • too many branches
  • too many returns
  • too many expressions
  • too many statements
  • too deep nesting

Function calls

  • no exec, eval, and compile
  • no vars(), no dir()
  • no print, pprint
  • no input
  • no globals(), no locals()
  • no short function names

Keywords

  • no global, no nonlocal, no del, no pass

Imports

  • no from some import * aka star-import
  • no from .. import some aka dot import
  • no nested imports
  • no __import__

Classes

  • no return/yield in __init__
  • no self override
  • self is not used
  • first method argument must be cls or self if not staticmethod
  • too few public method (__init__ + one other)
  • too many public methods
  • too many instance attributes
  • no magic methods: __del__
  • no attributes with default None: class Fixture: some_attribute = None

Variables

  • no blacklist variable names: data, result
  • no short variable names

Files

  • no bom
  • no long files, max-file-lines = 600
  • no logic in __init__.py
  • no __{}__ filenames, except __init__ and __main__

mypy

  • follow this pattern: x: List[SomeValue] = [], def cast(element: Element = None) -> str:

Add `__all__` to restricted metadata list

You should not define your API like that. Use naming conventions: public, _protected.
And you should not use from some import *. Use named imports.

So, we should ban this anti-pattern.

Implement `TooManyBranchesViolation`

When code has a lot of if, try, for, and other branches it is hard to follow what is going on.

We can restrict the number of logic branches allowed for a single function.
That's how it should work:

  • if is counted as +1 for the complexity, else and elif also counts as +1
  • for is counted as +1, else is also counted as +1
  • while is counted as +1
  • try is counted as +1, each except case is counted as +1
  • with is counted as +1

We need to figure out what number of branches is the most pleasant to have. We can consult pylint for this.

Implement TooDeepNestingViolation

We have to check that code like this:

class Test:
    def method(self):
        with some_manager():
            try:
                if self.call_method():
                    return True
            except:
                  return False

raises TooDeepNestingViolation error.

The optimal nesting level is 4. So, code under try should not have any nesting.

Forbid `__del__` magic method

You should not use __del__, as it is non-pythonic, more like cpp.

This method is not even called in several situations.
So, let's forbid it.

Forbid old-styled classes

In python2 we had different classes: class Some: and class Some(object): were totally different things.

Currently, we don't have this thing in python3, but since these times I believe that new-styled classes are still better.

  1. It has more semantics: this class is related to object
  2. It has unified interface: class Base(object) and class Child(Base) vs class Base and class Child(Base)
  3. Explicit is better than implicit

So, I believe we should ban classes with old-styled base class.
General rule is: always write super-classes' names

Correct

class Philosopher(object):
    def __init_subclass__(cls, default_name, **kwargs):
        ...

class AustralianPhilosopher(Philosopher, default_name="Bruce"):
    ...

class WithMetaClass(object, metaclass=MyMeta):
   ...

Wrong

class Philosopher: ...
class AustralianPhilosopher(default_name="Bruce"): ...
class WithMetaClass(metaclass=MyMeta): ...

Create configuration

Currently our linter is full of magic constants like:

What we need is:
0. create a file with default configuration values

  1. allow users to override these values with setup.cfg or any other standard flake8 tools
  2. test that when configuration is applied linter respects it

Forbid % string interpolation

As we have decided to stick to .format(), we are banning f strings: #32

But, @vergeev have also suggested to forbid 'string with %s' % some.
Here's the backstory:

  • gforcada/flake8-pep3101#23 has some false positives, that disallow to use regular modulo operator 5 % 2
  • we can only forbid using this operator with string literals, not vars as was suggested in #32 (comment)

So, this would be valid:

some_variable % 'value1'
5 % 2

This would be invalid:

'format me %s' % 'value2'

Django specific things

Models

  • no signal, because they are evil side effects
  • no BooleanField with null, use NullBooleanField
  • no CharField with null, use blank=True with possible '' as default
  • use CIEmailField instead of EmailField
  • no JSONField other than django.contrib.postgres.fields.JSONField
  • no default={} inJSONField, use default=dict instead
  • no methods on models except magic ones

Structure

  • all applications should be named as *_app
  • apps.py and models.py must be present
  • check filenames in *_app folder, whitelist: models, views, forms, admin, serializers, apps, urls, tasks, __init__

Test that nested classes also have explicit base classes

We need to be sure that cases like:

class Model(models.Model):
     class Meta: ...  # error here, needs explicit base class

are covered.

Correct way to write this example is:

class Model(models.Model):
     class Meta(object): ... 

This should work for all NESTED_CLASSES_WHITELIST.

Dependency "pluggy" may have a wrong hash in the lock file

When I do pipenv install -d on MacOS, the pluggy=0.6.0 dependency isn't getting installed because of the wrong hash: THESE PACKAGES DO NOT MATCH THE HASHES FROM Pipfile.lock!.

The package version pipenv tries to install is: https://files.pythonhosted.org/packages/ba/65/ded3bc40bbf8d887f262f150fbe1ae6637765b5c9534bd55690ed2c0b0f7/pluggy-0.6.0-py3-none-any.whl

The problem can be caused by pipenv itself (see pypa/pipenv#210).

Since I'm not sure I'm asking to verify that on other platforms.

Forbid "@" operator

It is used only for some data-science pacakges, which we obviously do not use.

Other usages of this operator different from matrix multiplications should be banned.

Test that `wemake-python-styleguide` is in `flake8` plugins

def test_call_flake8_version():
    """Checks that module is registered and visible in the meta data."""
    output = subprocess.check_output(
        ['flake8', '--version'],
        stderr=subprocess.STDOUT,
    )
    assert b'wemake-python-styleguide': ' in output

Forbid private variables

Names like __some_name should be forbiden, since there's no single use-case in python for real private variables.

Use public and protected variables instead.

Forbid `__future__` imports

They are not a thing in python3 anymore.
But, we should have a whitelist for things like annotations and some new features that might come.

I also feel like we should save some more error code for imports and move other errors up a bit.

Questions

I am not sure about these.

Classes

  • restrict passing attributes in __init_subclass__: class MyClass(MetaClass, option=1)

Allow the pass keyword inside a class that inherits from other classes

For example, the following is the only way in Django to inherit the Meta class:

class Meta(BaseModel.Meta):
    pass

But unfortunately it triggers WPS100 Found wrong keyword "pass".

More generally, the following should be allowed as it's a common thing to do:

class Foo(BarMixin, FooBase):
    pass

Right now the # noqa comment helps to avoid the warning.

Version 0.0.2 can't be used with pip

In some cases on line

node_parent = getattr(node, 'parent')

of WrongModuleMetadataVisitor we get

AttributeError: 'Assign' object has no attribute 'parent'

The bug can be fixed by the correct usage of getattr:

node_parent = getattr(node, 'parent', None)

The PR with the fix and a regression test will be ready in a day.

Restrict any logics inside `__init__.py`

Side effect inside __init__.py are nightmares.

We need to restrict any kind of python code inside __init__.py except:

  1. comments
  2. docstrings

Imports should be forbidden. Each separate module should have its own public API.

Disallow too broad `noqa` comments

Sometime I can see code like this:

try:
    import django  # noqa
except ImportError:
    pass

This bare noqa comment covers all possible issues on this line.
That's not what we want. We need to specify exact error numbers:

try:
    import django  # noqa: F401, Z101
except ImportError:
    pass

Forbid `getattr(x, 'foobar') `

As per the docs:

getattr(x, 'foobar') is equivalent to x.foobar

This may lead a reader to believe that getattr(obj, 'attribute') will not throw an exception.

Correct

x.foobar
getattr(x, 'foobar', None)
getattr(x, some_variable, None)

Incorrect

getattr(x, 'foobar')

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.