Tab (or Spaces) indentation style checker for flake
Project description
Tab (and Spaces) Style Checker for flake8 (flake8-tabs)
Like tabs? So do I!
This module provides a smart indentation checking module for the awesome
flake8
style checker suite, featuring
pycodestyle
,
pyflakes
and
mccabe
by default as well as a minimalist plugin architecture.
When enabled flake8-tabs will disable pycodestyle's “tabs_or_spaces”, “continued_indentation”, “tabs_obsolete” and “trailing_whitespace” checkers by default. Replacing them by its own more flexible checkers, that allow for the “tabs for indentation, spaces for alignment” paradgime to be applied to your source code – or simply getting a better indentation checker for your spaces based source code.
Table of Contents
Install
For interactive use (flake8
command) install using pip 19.1+:
$ pip install flake8-tabs
Or, if flake8
was installed via pipx add it that program's virtual environment instead:
$ pipx inject flake8 flake8-tabs
For adding flake8-tabs to your regular linting checks simply ensure that is mentioned in your
development requirements.txt
, tox configuration or wherever your linting
dependencies are stored in your project. There is no way in flake8 to enforce that a certain
linter is run when invoking the flake8
command, but you can use flake8 --help
to view the list
of plugins detected and active (last line of output).
There should be no issues when using this plugin with flake8 forks like flake9 or flakehell, but this has not been tested. Feedback welcome!
Usage
By default installing flake8-tabs will only enable the blank line indentation checker. To enable
flake8-tabs for your project proper, you will need to set the
use-flake8-tabs
option mentioned below to true.
All of the following options are specified using flake8's configuration system. See the relevant sections on invoking and configuring flake8 for details on how and where these options may be used.
Configuration options
Some of the below options will attempt to use read their defaults from the repository's .editorconfig file if one is found. Adding an EditorConfig file to your project is highly recommended as it will ensure that many code editors will automatically set their editing preferences based on your project's expectations. By using these values by default flake8-tabs saves you from duplicating this configuration between that file and your linter.
All other option defaults, as well as all ultimate defaults tend to reflect recommendations from PEP-8.
Note: In the following, indenting refers to the practice of adding new levels of indentation (usually using tab key whether you're using tabs or not) on a separate line, while aligning refers to the practice of adding spacing in front of the elements on the following line to make them visually match the elements on the previous line. Indentation may refer to any of the above.
use-flake8-tabs
- Default: false
- Allowed values: true, false
Enable flake8-tabs for indentation checking and, by default, disable the all conflicting checkers
from pycodestyle (see next option). Without setting this to true, or passing --use-flake8-tabs
on the command-line, only flake8-tabs's blank line indentation checking will be enabled. While this
flag is disabled it is guaranteed no errors will be reported where pycodestyle will not report
one as well. While further checks may be enabled at some point that do not require use of this
flag, they will not ever break this guarantee.
This way you can selectively disable errors from pycodestyle and incrementally depend on the smarter checkers in flake8-tabs.
use-pycodestyle-indent
- Default: false if
use-flake8-tabs
is true otherwise true - Allowed values: true, false
If false indentation style checks from pycodestyle will be disabled, see the description of the previous option for details.
indent-style
- Default:
indent_style
property of .editorconfig or "keep" if unset / not found - Allowed values: "tab", "space", "keep"
The indentation style to expect in newly indented code blocks. By default flake8-tabs will simply analyze what is already there and only ensure that no inconsistent mixture of both tabs and spaces in the same code block happens. This allows different files, and even different code blocks in the same file, to use different indentation styles; generally you'll want to pick one and stick with it.
tab-width
- Default:
indent_size
property of .editorconfig or 4 if unset / not found - Allowed values: Any integer >= 1
The expected size of each tab in spaces. This is not really specific to this plugin, but used to properly calculate the required additional spaced indentation when indenting within an aligned section.
Internally this value is also used to monkeypatch flake8's pretty printing function to expand tabs to this number of spaces instead of its hard-coded default of 8 spaces per tab.
blank-lines-indent
- Default depends on
trim_trailing_whitespace
property of .editorconfig:- "never" if true
- "always" if false
- "maybe" if unset / not found
- Allowed values: "maybe", "always", "never"
Whether to allow properly aligned indentation in blank lines. The default value will allow both aligned indentation and no indentation. "always" will require blank lines to contain indentation, "never" will prohibit it.
By properly aligned indentation we mean indentation that has the same value as the indentation of the next block of source code:
# This is OK (matching indent):
def main():
↹ # … snip …
↹ do_something()
↹
↹ do_something_else()
↹ # … snip …
# This is not OK (unmatching indent):
def main():
↹ while True:
↹ ↹ # … snip …
↹ ↹ do_something()
↹
↹ ↹ do_something_else()
↹ ↹ # … snip …
# This is by default OK as well (unindented):
def main():
↹ while True:
↹ ↹ # … snip …
↹ ↹ do_something()
↹ ↹ do_something_else()
↹ ↹ # … snip …
Note that this checker does not ensure that the blank line indentation style is consistent within a document when set to "maybe", so the following will pass by default but may not be what you want:
def main():
↹ while True:
↹ ↹ # … snip …
↹ ↹ do_something()
↹ ↹ do_something_else()
↹ ↹
↹ ↹ do_more()
↹ ↹ # … snip …
Please open an issue if ensuring consistent per-document blank line indentation is something you need.
continuation-style
- Default: "both"
- Allowed values: "aligned", "hanging", "both"
By default flake8-tabs allows lines following the initial line belonging to the same statement (“continuation lines”) to either align to the innermost opened bracket of the preceeding line or use 1–2 levels of indenting (see the next set of options) depending on whether the previous line ended with an opening bracket or not:
# Example for aligned indentation (OK with continuation-style=aligned|both):
def foo_bar(x: int,
␣␣␣␣␣␣␣␣␣␣␣␣y: int) -> str: # The “y” matches up with the “x” above
↹ return f"{x}, {y}"
# Same code with hanging indentation (OK with continuation-style=hanging|both):
def foo_bar( # This line ends with an opening bracket
↹ ↹ x: int,
↹ ↹ y: int,
) -> str:
↹ return f"{x}, {y}"
This option can be used to restrict the allowed continuation style to only one of the above
(PEP-8 allows both with semantics very similar to the ones mentioned above). In particular,
setting continuation-style
to "hanging" will ensure that flake8-tabs will never allow
a line to contain both spaces and tabs at the same time.
Indenting Tab Counts
When using hanging indentation on a continuation line, the following options may be used to
configurate the number of tabs expected on the continuation line. These options are not very
useful if continuation-style
is set to "aligned".
(Note that a tab here may also refer to an equivalent number of spaces based on the configured tab width.)
indent-tabs-call
- Default: 1
- Allowed values: Any integer >= 1
The number of tabs to add when adding the first level of indentation using indenting within a function or method call:
# Example with: indent-tabs-call=3
x = long_function_name(
↹ ↹ ↹ { # First level gets 3 levels of indenting
↹ ↹ ↹ ↹ "name": "value" # Next level is indented as usual
↹ ↹ ↹ },
↹ ↹ ↹ param2, param3
)
Usually you should leave this at 1 (PEP-8) but some teams may prefer a value of 2 to function calls more easily distinguishable from blocks.
indent-tabs-def
- Default: 2
- Allowed values: Any integer >= 1
The number of tabs to add when adding the first level of indentation using indenting within a class of method definition:
# Example with the default of: indent-tabs-def=2
def main(
↹ ↹ param1, param2, param3,
↹ ↹ param4):
↹ initialize_something()
)
Notice in the example above how an indent level of 1 would make the elements of the parameter list hard to distingish from the first statement. Hence PEP-8 recommends either indenting twice or using alignment instead.
indent-tabs-expr
- Default: 1
- Allowed values: Any integer >= 1
The number of tabs to add when adding the first level of indentation using indenting within any other kind of construct (such as a tuple, set, dict, …).
Reported Error Codes
All error codes were borrowed from pycodestyle. You can detect that they were generated by
flake8-tabs by them being followed by the word (flake8-tabs)
as well as the extra T
added
after the initial severity letter.
Error Code | Meaning |
---|---|
ET101 | Mixed block of tabs and spaces detected where there as a least one tab following a space |
ET121, ET122, ET123, ET126, ET127, ET128 | Identation did not match what was expected (somewhat configurable) |
WT291 | Extranous whitespace detected on end of line |
WT293 | Whitespace that was not aligned with the surrounding source detected (configurable) |
Also note that, due to the way we disable the relevant checkers from pycodestyle the following error codes do not have an equivalent in this plugin: E124, E125, E129, E131, E133.
Alternatives
- flake8-expandtab replaces all tabs in the input
document with a configurable number of spaces before it is passed to pycodestyle
-
Comment: While its code is a lot simpler, this approach does not prevent inappropriate mixing of tabs and spaces on the same line. It will silently allow documents that will look broken when viewed with a different tab width setting and will even fail to detect documents that are invalid Python due to unparsable mixed spaces/tabs usage.
That said, it was the primary inspiration for developing this checker in the first place.
-
Contributing
As usual, contributions to the project are welcome!
Please report issues and feature requests at https://gitlab.com/ntninja/flake8-tabs/-/issues/ (requires GitLab.com account) after verifying that it hasn't already been reported. In cases where you believe that flake8-tabs is incorrectly reporting a violation or should report a violation that it is currently not, please include a minimum affected code sample and any reported violations you are currently seeing.
If you cannot or don't want to create a GitLab.com account, feel free to instead contact me via email at alexander-f8t@ninetailed.ninja instead. However, please use GitLab instead if you can as it helps me keep things organized.
Code and documentation contributions are of course also welcome. If your new to forking and merge requests on GitLab this short guide should come in handy. If you need help with anything, feel free to open an issue and I'll try to guide you through the process if needed.
As with reporting issues you may also contact me via email with patches if using GitLab.com is not possible for you. Again, using GitLab.com is strongly preferred however.
Setting up a local development environment
flake8-tabs uses PDM for its Python project management needs. Please refer to its installation instructions before continuting. (Using the pipx based installation method on Linux is highly recommended: As of March 2021, the virtualenv preloading packages shipped with some distros may cause weird version-conflict related errors in the author's experience.)
After installing PDM, prepare the development environment using:
$ pdm install --dev
Your locally modified version of flake8-tabs may now be invoked using pdm run
:
$ pdm run flake8 […]
You can also run your modified version from another directory (such as a project of yours where
flake8-tabs exhibits some bad behaviour) using the -p
option of pdm run
:
~/path/to/your/project$ pdm run -p ~/path/to/flake8-tabs flake8 […]
License
This project is licensed under the GNU Lesser General Public License version 3.0 or (at your option) any later version.
For the full license, please consult the LICENSE.md file distributed along with this project.
Copyright owners are:
- 2017–2021 Alexander Schlarb
- 2020 Peter Linss
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for flake8_tabs-2.3.2-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f11c4b8a1537d67014c24f5296118e54b78fc43204b740e28283fa8e165130ef |
|
MD5 | 110edcc06ed0b08355ea51079dd2af43 |
|
BLAKE2b-256 | 2d96a4d857b4d47349b0ceeeef1002d624c1907e7690a8ced8c3ce11c7b2101d |