bellybutton
is a customizable, easy-to-configure linting engine for Python.
Tools like pylint and flake8 provide, out-of-the-box, a wide variety of rules for enforcing Python best practices, ensuring PEP-8 compliance, and avoiding frequent sources of bugs. However, many projects have project-specific candidates for static analysis, such as internal style guides, areas of deprecated functionality, or common sources of error. This is especially true of those projects with many contributors or with large or legacy codebases.
bellybutton
allows custom linting rules to be specified on a per-project basis and detected as part of
your normal build, test and deployment process and, further, makes specifying these rules highly
accessible, greatly lowering the cost of adoption.
Give bellybutton
a try if:
- You find yourself making the same PR comments over and over again
- You need a means of gradually deprecating legacy functionality
- You're looking to build a self-enforcing style guide
- Your project needs to onboard new or junior developers more quickly and effectively
- You have Python nitpicks that go beyond what standard linting tools enforce
bellybutton
can be installed via:
pip install bellybutton
Once installed, running
bellybutton init
in your project's root directory will create a .bellybutton.yml
configuration file with an example
rule for you to begin adapting. bellybutton
will also try to provide additional rule settings based
on the directory structure of your project.
Once you have configured bellybutton
for your project, running
bellybutton lint
will lint the project against the rules specified in your .bellybutton.yml
. Additionally, running
bellybutton lint --modified-only
will, if using git, only lint those files that differ from origin/master
.
For adding bellybutton
to your CI pipeline, take a look at this repository's tox configuration
and .travis.yml as an example.
Rules in bellybutton
supply patterns that should be caught and cause linting to fail. Rules as specified
in your .bellybutton.yml
configuration must consist of:
- A description
description
, expressing the meaning of the rule - An expression
expr
, specifying the pattern to be caught - either as an astpath expression or as a regular expression (!regex ...
).
Additionally, the key used for the rule within the rules
mapping serves as its name.
Rules may also consist of:
- Settings
settings
that specify on which files the rule is to be enforced, as well as whether it can be ignored via a# bb: ignore
comment - An example
example
of Python code that would be matched by the rule - A counter-example
instead
of an alternative piece of code, for guiding the developer in fixing their linting error.
These example
and instead
clauses are checked at run-time to ensure that they respectively are and are not
matched by the rule's expr
.
As an example, a rule to lint for a deprecated function call using an astpath expression might look like:
DeprecatedFnCall:
description: `deprecated_fn` will be deprecated in v9.1.2. Please use `new_fn` instead.
expr: //Call[func/Name/@id='deprecated_fn']
example: "deprecated_fn(*values)"
instead: "new_fn(values)"
!settings
nodes specify:
included
paths on which rules are to be run, using glob notationexcluded
paths on which rules are not to be run (even when matching theincluded
paths)- A boolean
allow_ignore
which determines whether rules can be ignored, providing the line matching the rule has a# bb: ignore
comment.
Additionally, at the root level of .bellybutton.yml
, a default_settings
setting may be specified which
will be used by rules without explicit settings. Each rule must either have a settings
parameter or be
able to fall back on the default_settings
.
As an example, a !settings
node to lint only a specific module might look like:
my_module_settings: !settings
included:
- ~+/my_package/my_module.py
excluded: []
allow_ignore: no
Check out this repository's .bellybutton.yml
as an example bellybutton
configuration file,
and astpath
's README for examples of the types
of patterns you can lint for using bellybutton
.
bellybutton
is in an alpha release and, as such, is missing some key features, documentation,
and full test coverage. Further, bellybutton
is not optimized for performance on extremely large
codebases and may contain breaking bugs. Please report any bugs encountered.
- The
!chain
and!verbal
expression nodes are not yet implemented
- Name: H. Chase Stevens
- Twitter: @hchasestevens