Getting Started
Use pip install fixit
to install Fixit.
Analyze Code Issues and Autofix Issues
Given an example code (example.py
) like this:
[2]:
%%writefile $file_path
from typing import Dict
class C(object):
attr = "ab" "cd" "ef" "gh"
def method(self) -> Dict[int, str]:
filtered_char = []
for char in self.attr:
if char is not "a":
filtered_char.append(char)
index_to_char = dict([(idx, char) for idx, char in enumerate(filtered_char)])
return index_to_char
Writing /tmp/tmpzhdozjsb/example.py
We can run Fixit rules to check code issues:
[4]:
! python -m fixit.cli.run_rules
Scanning 1 files
Testing 33 rules
example.py:4:1
NoInheritFromObjectRule: Inheriting from object is a no-op. 'class Foo:' is
just fine =)
example.py:5:12
UsePlusForStringConcatRule: Implicit string concatenation detected, please
add '+' to be explicit. E.g. a tuple or a call ("a" "b") with a missing
comma results in multiple strings being concatenated as one string and
causes unexpected behaviour.
example.py:10:16
ComparePrimitivesByEqualRule: Don't use `is` or `is not` to compare
primitives, as they compare references. Use == or != instead.
example.py:13:25
RewriteToComprehensionRule: It's unnecessary to use a list comprehension
inside a call to dict since there are equivalent comprehensions for this
type
Found 4 reports in 1 files in 0.56 seconds.
Each warning shows the violation’s position in the format of file_name:starting_line_number:starting_column_number
, follwed by the lint rule name and lint message.
To fix the issues automatically:
[5]:
! python -m fixit.cli.apply_fix
Scanning 1 files
./example.py
example.py:4:1 [applied fix]
NoInheritFromObjectRule: Inheriting from object is a no-op. 'class Foo:' is
just fine =)
example.py:5:12 [applied fix]
UsePlusForStringConcatRule: Implicit string concatenation detected, please
add '+' to be explicit. E.g. a tuple or a call ("a" "b") with a missing
comma results in multiple strings being concatenated as one string and
causes unexpected behaviour.
example.py:10:16 [applied fix]
ComparePrimitivesByEqualRule: Don't use `is` or `is not` to compare
primitives, as they compare references. Use == or != instead.
example.py:13:25 [applied fix]
RewriteToComprehensionRule: It's unnecessary to use a list comprehension
inside a call to dict since there are equivalent comprehensions for this
type
reformatted -
All done! ✨ 🍰 ✨
1 file reformatted.
Found 4 reports in 1 files in 3.17 seconds.
All the issues are automatically fixed!
[6]:
! git diff
diff --git a/example.py b/example.py
index aed4bb5..3f667f8 100644
--- a/example.py
+++ b/example.py
@@ -1,14 +1,14 @@
from typing import Dict
-class C(object):
- attr = "ab" "cd" "ef" "gh"
+class C:
+ attr = "ab" + "cd" + "ef" + "gh"
def method(self) -> Dict[int, str]:
filtered_char = []
for char in self.attr:
- if char is not "a":
+ if char != "a":
filtered_char.append(char)
- index_to_char = dict([(idx, char) for idx, char in enumerate(filtered_char)])
+ index_to_char = {idx: char for idx, char in enumerate(filtered_char)}
return index_to_char
Configuration File
A Fixit configuration file allows you to configure Fixit settings for your codebase.
To initialize a configuration file populated with some defaults, run:
python -m fixit.cli.init_config
This will create a
.fixit.config.yaml
with default settings in the current working directory.
Next, you may wish to edit or add some specific settings. The available configurations are:
allow_list_rules
: A list of rules (whether custom of from Fixit) that should be applied to the repository. Omitting this setting allows all rules to run. For example:allow_list_rules: [Flake8PseudoLintRule]
block_list_rules
takes precendence, so if a rule is in both allow_list_rules
and block_list_rules
the rule will not be run.
block_list_patterns
: A list of patterns that indicate that a file should not be linted. For example:block_list_patterns: ['@generated', '@nolint']
will tell Fixit to skip linting any files that have
@generated
or@nolint
in their contents.block_list_rules
: A list of rules (whether custom or from Fixit) that should not be applied to the repository. For example:block_list_rules: [NoInheritFromObjectRule]
fixture_dir
: The directory in which fixture files required for unit testing are to be found. This is only necessary if you are testing rules that use a metadata cache (see AwaitAsyncCallRule for an example of such a rule). This can be an absolute path, or a path relative to repo_root (see below).use_noqa
: Defaults toFalse
. UseTrue
to support Flake8 lint suppression comment: noqa. The noqa is not recommended because a bare noqa implicitly silences all lint errors which prevent other useful lint errors to show up. We recommend uselint-fixme
orlint-ignore
suppression comments.formatter
: A list of the formatter commands to use after a lint is complete. These will be passed to theargs
parameter in subprocess.check_output in the order in which they appear. For example:formatter: [black, '-']
Here, the formatter of choice would be Black and the added
-
tells it to read from standard input, and write to standard output so that it is compatible with Fixit’s formatting logic.packages
: The Python packages in which to search for lint rules. For example:packages: [fixit.rules, my.custom.package]
repo_root
: The path to the repository root. This can be a path relative to the .fixit.config.yaml file or an absolute path. For example:repo_root: .
rule_config
: Rule-specific configurations. For example:ImportConstraintsRule: fixit: rules: [["*", "allow"]]
(see ImportConstraintsRule for more details on this example)
A .fixit.config.yaml example with populated settings:
block_list_patterns: - '@generated' - '@nolint' block_list_rules: - BlockListedRule fixture_dir: ./tests/fixtures formatter: - black - '-' packages: - fixit.rules repo_root: . rule_config: ImportConstraintsRule: fixit: rules: [["*", "allow"]]
Enforcing Custom Rules
After finishing up the configuration, you may wish to enforce some custom lint rules in your repository.
1. Start by creating a directory where your custom rules will live. Make sure to include an __init__.py
file so that the directory is importable as a package.
This can simply be an empty file. For example:
my_repo_root
└── lint
└── custom_rules
└── __init__.py
Include the dotted name of the package in the .fixit.config.yaml file under the packages setting:
packages: - fixit.rules - lint.custom_rules
See the Build a Lint Rule page for more details on how to write the logic for a custom lint rule.
Running Lint Rules
You may also want to run some rules against your repository to see all current violations.
To run only the pre-packaged Fixit rules against the entire repository, run:
python -m fixit.cli.run_rules --rules fixit.rules
To run only your custom rules package against the entire repository, run:
python -m fixit.cli.run_rules --rules <dotted_name_of_custom_package>
To run a specific rule against the entire repository, run:
python -m fixit.cli.run_rules --rules <rule_name>
To run all the rule packages under the
packages
settings in the .fixit.config.yaml file against the entire repository, run:python -m fixit.cli.run_rules
To run all the rule packages under the
packages
settings in the .fixit.config.yaml file against a particular file or directory, run:python -m fixit.cli.run_rules <file_or_directory>
To run all the rule packages under the
packages
settings in the .fixit.config.yaml file against mutliple files or directories, run:python -m fixit.cli.run_rules <file_or_directory> <file_or_directory2> <file_or_directory3>
Applying Autofixes
Some rules come with provided autofix suggestions. We have provided a script to help you automatically apply these suggested fixes. To do this, run:
python -m fixit.cli.apply_fix <file_or_directory> --rules <rule_name_or_package>
This will apply one or more lint rules’ autofix to the source code in the specified file(s) or directory.
For more detailes on this script’s usage, run:
python -m fixit.cli.apply_fix --help
Suppressing Violations
You may wish to suppress existing lint violations from the lint engine altogether. We have provided a script to help you automatically insert lint suppressions. To do this, run:
python -m fixit.cli.insert_suppressions <rule_name> <file_or_directory>
This will insert a suppression in the form of a # lint-fixme
comment above lines in the source code that violate the specified rule.
For more detailes on this script’s usage, run:
python -m fixit.cli.insert_suppressions --help