All Projects → MartinThoma → flake8-simplify

MartinThoma / flake8-simplify

Licence: MIT license
❄ A flake8 plugin that helps you to simplify code

Programming Languages

python
139335 projects - #7 most used programming language

Projects that are alternatives of or similar to flake8-simplify

Wemake Python Styleguide
The strictest and most opinionated python linter ever!
Stars: ✭ 1,714 (+1667.01%)
Mutual labels:  linter, flake8, code-quality, flake8-plugin
flake8-broken-line
🚨 Flake8 plugin to forbid backslashes (\) for line breaks
Stars: ✭ 85 (-12.37%)
Mutual labels:  linter, flake8, code-quality, flake8-plugin
flake8-aaa
A Flake8 plugin that checks Python tests follow the Arrange-Act-Assert pattern
Stars: ✭ 51 (-47.42%)
Mutual labels:  linter, code-quality, flake8-plugin
flake8-type-checking
Flake8 plugin for managing type-checking imports & forward references.
Stars: ✭ 38 (-60.82%)
Mutual labels:  flake8, flake8-plugin, flake8-extensions
Editorconfig Checker
A tool to verify that your files are in harmony with your .editorconfig
Stars: ✭ 119 (+22.68%)
Mutual labels:  linter, code-quality
Static Analysis
⚙️ A curated list of static analysis (SAST) tools for all programming languages, config files, build tools, and more.
Stars: ✭ 9,310 (+9497.94%)
Mutual labels:  linter, code-quality
Flake8 Eradicate
Flake8 plugin to find commented out or dead code
Stars: ✭ 184 (+89.69%)
Mutual labels:  linter, code-quality
Dotenv Linter
☺️ Linting dotenv files like a charm!
Stars: ✭ 207 (+113.4%)
Mutual labels:  linter, code-quality
Flakehell
Flake8 wrapper to make it nice, legacy-friendly, configurable.
Stars: ✭ 217 (+123.71%)
Mutual labels:  linter, code-quality
flake8-putty
Flake8 plugin to control reporting per file and line
Stars: ✭ 38 (-60.82%)
Mutual labels:  linter, flake8-plugin
sonar-css-plugin
SonarQube CSS / SCSS / Less Analyzer
Stars: ✭ 46 (-52.58%)
Mutual labels:  linter, code-quality
Sonar Jproperties Plugin
SonarQube Java Properties Analyzer
Stars: ✭ 5 (-94.85%)
Mutual labels:  linter, code-quality
flake8-mypy
A plugin for flake8 integrating Mypy.
Stars: ✭ 103 (+6.19%)
Mutual labels:  linter, flake8
flake8-annotations
Flake8 Type Annotation Checking
Stars: ✭ 117 (+20.62%)
Mutual labels:  flake8, flake8-plugin
Cflint
Static code analysis for CFML (a linter)
Stars: ✭ 156 (+60.82%)
Mutual labels:  linter, code-quality
Sonarts
Static code analyzer for TypeScript
Stars: ✭ 776 (+700%)
Mutual labels:  linter, code-quality
Undercover
Actionable code coverage - detects untested code blocks in recent changes
Stars: ✭ 574 (+491.75%)
Mutual labels:  linter, code-quality
elm-review
Analyzes Elm projects, to help find mistakes before your users find them.
Stars: ✭ 195 (+101.03%)
Mutual labels:  linter, code-quality
Flake8 Bugbear
A plugin for Flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle.
Stars: ✭ 518 (+434.02%)
Mutual labels:  linter, code-quality
Pep8speaks
A GitHub app to automatically review Python code style over Pull Requests
Stars: ✭ 546 (+462.89%)
Mutual labels:  linter, code-quality

PyPI version Code on Github Actions Status Code style: black

flake8-simplify

A flake8 plugin that helps you simplify your code.

Installation

Install with pip:

pip install flake8-simplify

Python 3.6 to 3.8 are supported.

Usage

Just call flake8 . in your package or flake your.py:

$ flake8 .
./foo/__init__.py:690:12: SIM101 Multiple isinstance-calls which can be merged into a single call for variable 'other'

Rules

Python-specific rules:

Simplifying Comparations:

Simplifying usage of dictionaries:

  • SIM401: Use 'a_dict.get(key, "default_value")' instead of an if-block (example)
  • SIM118: Use 'key in dict' instead of 'key in dict.keys()' (example)

General Code Style:

Experimental rules:

Getting rules right for every possible case is hard. I don't want to disturb peoples workflows. For this reason, flake8-simplify introduces new rules with the SIM9 prefix. Every new rule will start with SIM9 and stay there for at least 6 months. In this time people can give feedback. Once the rule is stable, the code will change to another number.

Current experimental rules:

  • SIM901: Use comparisons directly instead of wrapping them in a bool(...) call (example)
  • SIM904: Assign values to dictionary directly at initialization (example)
  • SIM905: Split string directly if only constants are used (example)
  • SIM906: Merge nested os.path.join calls (example)
  • SIM907: Use Optional[Type] instead of Union[Type, None] (example)
  • SIM908: Use dict.get(key) (example)
  • SIM909: Avoid reflexive assignments (example)

Disabling Rules

You might have good reasons to ignore some flake8 rules. To do that, use the standard Flake8 configuration. For example, within the setup.cfg file:

[flake8]
ignore = SIM106, SIM113, SIM119, SIM9

Examples

SIM101

# Bad
isinstance(a, int) or isinstance(a, float)

# Good
isinstance(a, (int, float))

SIM102

# Bad
if a:
    if b:
        c

# Good
if a and b:
    c

SIM105

# Bad
try:
    foo()
except ValueError:
    pass

# Good
from contextlib import suppress

with suppress(ValueError):
    foo()

Please note that contextlib.suppress is roughly 3x slower than try/except (source).

SIM107

# Bad: This example returns 3!
def foo():
    try:
        1 / 0
        return "1"
    except:
        return "2"
    finally:
        return "3"


# Good
def foo():
    return_value = None
    try:
        1 / 0
        return_value = "1"
    except:
        return_value = "2"
    finally:
        return_value = "3"  # you might also want to check if "except" happened
    return return_value

SIM108

# Bad
if a:
    b = c
else:
    b = d

# Good
b = c if a else d

SIM109

# Bad
if a == b or a == c:
    d

# Good
if a in (b, c):
    d

SIM110

# Bad
for x in iterable:
    if check(x):
        return True
return False

# Good
return any(check(x) for x in iterable)

SIM111

# Bad
for x in iterable:
    if check(x):
        return False
return True

# Good
return all(not check(x) for x in iterable)

SIM112

# Bad
os.environ["foo"]
os.environ.get("bar")

# Good
os.environ["FOO"]
os.environ.get("BAR")

SIM113

Using enumerate in simple cases like the loops below is a tiny bit easier to read as the reader does not have to figure out where / when the loop variable is incremented (or if it is incremented in multiple places).

# Bad
idx = 0
for el in iterable:
    ...
    idx += 1

# Good
for idx, el in enumerate(iterable):
    ...

SIM114

# Bad
if a:
    b
elif c:
    b

# Good
if a or c:
    b

SIM115

# Bad
f = open(...)
...  # (do something with f)
f.close()

# Good
with open(...) as f:
    ...  # (do something with f)

SIM116

# Bad
if a == "foo":
    return "bar"
elif a == "bar":
    return "baz"
elif a == "boo":
    return "ooh"
else:
    return 42

# Good
mapping = {"foo": "bar", "bar": "baz", "boo": "ooh"}
return mapping.get(a, 42)

SIM117

# Bad
with A() as a:
    with B() as b:
        print("hello")

# Good
with A() as a, B() as b:
    print("hello")

Thank you for pointing this one out, Aaron Gokaslan!

SIM118

# Bad
key in a_dict.keys()

# Good
key in a_dict

Thank you for pointing this one out, Aaron Gokaslan!

SIM120

# Bad
class FooBar(object):
    ...


# Good
class FooBar:
    ...

Both notations are equivalent in Python 3, but the second one is shorter.

SIM201

# Bad
not a == b

# Good
a != b

SIM202

# Bad
not a != b

# Good
a == b

SIM203

# Bad
not a in b

# Good
a not in b

SIM208

# Bad
not (not a)

# Good
a

SIM210

# Bad
True if a else False

# Good
bool(a)

SIM211

# Bad
False if a else True

# Good
not a

SIM212

# Bad
b if not a else a

# Good
a if a else b

SIM220

# Bad
a and not a

# Good
False

SIM221

# Bad
a or not a

# Good
True

SIM222

# Bad
... or True

# Good
True

SIM223

# Bad
... and False

# Good
False

SIM300

# Bad; This is called a "Yoda-Condition"
42 == age

# Good
age == 42

SIM401

# Bad
if key in a_dict:
    value = a_dict[key]
else:
    value = "default_value"

# Good
thing = a_dict.get(key, "default_value")

SIM901

This rule will be renamed to SIM224 after its 6-month trial period is over. Please report any issues you encounter with this rule!

The trial period starts on 23rd of January and will end on 23rd of August 2022.

# Bad
bool(a == b)

# Good
a == b

SIM904

This rule will be renamed to SIM224 after its 6-month trial period is over. Please report any issues you encounter with this rule!

The trial period starts on 12th of February and will end on 12th of September 2022.

# Bad
a = {}
a["b"] = "c"

# Good
a = {"b": "c"}

SIM905

This rule will be renamed to SIM225 after its 6-month trial period is over. Please report any issues you encounter with this rule!

The trial period starts on 13th of February and will end on 13th of September 2022.

# Bad
domains = "de com net org".split()

# Good
domains = ["de", "com", "net", "org"]

SIM906

This rule will be renamed to SIM126 after its 6-month trial period is over. Please report any issues you encounter with this rule!

The trial period starts on 20th of February and will end on 20th of September 2022.

# Bad
os.path.join(a, os.path.join(b, c))

# Good
os.path.join(a, b, c)

SIM907

This rule will be renamed to SIM127 after its 6-month trial period is over. Please report any issues you encounter with this rule!

The trial period starts on 28th of March and will end on 28th of September 2022.

# Bad
def foo(a: Union[int, None]) -> Union[int, None]:
    return a


# Good
def foo(a: Optional[int]) -> Optional[int]:
    return a

SIM908

This rule will be renamed to SIM121 after its 6-month trial period is over. Please report any issues you encounter with this rule!

The trial period starts on 28th of March and will end on 28th of September 2022.

# Bad
name = "some_default"
if "some_key" in some_dict:
    name = some_dict["some_key"]

# Good
name = some_dict.get("some_key", "some_default")

SIM909

Thank you Ryan Delaney for the idea!

This rule will be renamed to SIM124 after its 6-month trial period is over. Please report any issues you encounter with this rule!

The trial period starts on 28th of March and will end on 28th of September 2022.

# Bad
foo = foo

# Good: Nothing. Reflexive assignments have no purpose.

or

# Bad
foo = foo = 42

# Good
foo = 42
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].