Pylint is a tool that checks your Python code to help you find mistakes, follow coding standards, and make your code easier to read and maintain.
It looks through your code without running it, spots errors, checks for style issues, and suggests ways to improve or clean up your code.
This guide will show you how to install Pylint, use its features, set it up for your projects, and make it part of your regular development routine.
Prerequisites
Before you get started, make sure you have a recent version of Python (3.9 or higher) and that pip
is installed
Setting up the project environment
In this section, you'll set up a brand-new Python project to show how Pylint works.
Start by creating a new folder for your project and go into it. After that, set up a virtual environment to keep your project's dependencies separate from everything else:
mkdir pylint-demo && cd pylint-demo
python3 -m venv venv
Activate your virtual environment:
source venv/bin/activate
Now, create a simple Python file with common issues that will showcase Pylint's detection capabilities:
import os
import sys
def calculate_average(numbers):
unused = "This variable is never used"
if numbers == None:
return 0
total = 0
for num in numbers:
total += num
return total / len(numbers)
def process_data(data):
try:
result = calculate_average(data)
print("Average:", result)
except:
print("Error occurred")
if __name__ == "__main__":
test_data = [1, 2, 3, 4, 5]
process_data(test_data)
With this foundation in place, you're ready to explore Pylint's analysis capabilities.
Getting started with Pylint
In this section, you'll install Pylint and run your first analysis to understand how it identifies code quality issues and potential improvements.
Start by installing Pylint in your virtual environment:
pip install pylint
Now, run Pylint against your sample code to see what it discovers:
pylint index.py
You should see detailed output similar to this:
************* Module index
index.py:1:0: C0114: Missing module docstring (missing-module-docstring)
index.py:5:0: C0116: Missing function or method docstring (missing-function-docstring)
index.py:8:7: C0121: Comparison 'numbers == None' should be 'numbers is None' (singleton-comparison)
index.py:6:4: W0612: Unused variable 'unused' (unused-variable)
index.py:18:0: C0116: Missing function or method docstring (missing-function-docstring)
index.py:22:4: W0702: No exception type(s) specified (bare-except)
index.py:1:0: W0611: Unused import os (unused-import)
index.py:2:0: W0611: Unused import sys (unused-import)
-----------------------------------
Your code has been rated at 5.79/10
Notice how Pylint provides comprehensive feedback with color-coded severity levels:
- C (Convention): Issues with coding standards like missing docstrings
- W (Warning): Potential problems like unused imports or variables
- R (Refactor): Suggestions for code improvement like unnecessary else blocks
- E (Error): Likely bugs that could cause runtime failures
- F (Fatal): Critical issues that prevent analysis
Pylint categorizes its findings into five distinct levels of increasing severity, each represented by a letter, helping you prioritize which issues to address first.
The analysis completes quickly and provides a comprehensive code quality score, making it easy to track improvements over time.
Customizing Pylint configuration
Pylint's extensive configurability allows you to tailor its behavior to match your project's specific requirements and coding standards.
Generate a comprehensive configuration file using Pylint's built-in generator:
pylint --generate-rcfile > .pylintrc
This creates a detailed .pylintrc
file containing all available configuration options with their default values. The generated file is quite extensive - typically over 400 lines - and serves as both a reference and starting point for customization.
The configuration file is organized into logical sections that control different aspects of Pylint's behavior:
- [MAIN]: Core settings like which files to analyze, plugins to load, and parallel processing options
- [MESSAGES CONTROL]: Controls which warnings and errors to enable or disable - the most commonly customized section
- [FORMAT]: Code formatting rules including line length, indentation, and module size limits
- [DESIGN]: Structural guidelines like maximum function arguments, class attributes, and code complexity
- [BASIC]: Naming conventions for variables, functions, classes, and other identifiers
- [SIMILARITIES]: Settings for detecting duplicate code blocks
To customize Pylint's behavior, simply edit the sections you want to change in the generated .pylintrc
file. You don't need to understand every option - just modify the parts relevant to your needs and run Pylint again to see the changes take effect.
For example, let's make a key adjustment that will significantly speed up analysis on larger projects. Edit this section in your .pylintrc
file:
[MAIN]
# Change jobs from 1 to 0 to use all available CPU cores
jobs=0
# Add common directories to ignore to speed up analysis
ignore=CVS,
.git,
__pycache__,
.pytest_cache,
venv,
.venv,
env,
.env,
node_modules,
build,
dist
This single change can make Pylint run 2-4x faster on multi-core systems by enabling parallel processing, while also preventing it from analyzing irrelevant directories that would just create noise.
After making this change, run Pylint again:
pylint index.py
You'll notice the analysis completes much faster, and the output remains the same quality:
For legacy projects where Pylint was never enforced, it's recommended to start with the --errors-only
flag, then disable convention and refactor messages with --disable=C,R
and progressively re-evaluate as your priorities evolve.
You can also create project-specific overrides by placing different .pylintrc
files in subdirectories, or specify a custom configuration file location:
pylint --rcfile=path/to/custom-config sample_code.py
This flexibility allows you to maintain consistent standards across different parts of your project while accommodating specific requirements.
Managing false positives and exceptions
Even with a good configuration, Pylint sometimes flags code that you've written in a certain way intentionally, or it might complain about things that are fine in your specific situation. Instead of turning off checks completely in your configuration file, you can tell Pylint to ignore specific warnings exactly where they happen.
Understanding when to disable warnings
Let's create a file with some intentional code patterns that Pylint will complain about:
import json
# Variable name that breaks naming conventions but is clearer
API_v2_client = SomeAPIClient()
def load_config_file(filename):
"""Load configuration file with broad exception handling."""
try:
with open(filename, 'r') as f:
return json.load(f)
except Exception:
# We actually want to catch all exceptions here for safety
return load_default_config()
# Legacy function that can't be easily changed
def complex_calculation(a, b, c, d, e, f):
"""Old function with many parameters - changing it would break things."""
return (a + b) * (c + d) + (e * f)
Run Pylint on this file to see what it complains about:
pylint example_suppressions.py
You'll see output like this:
************* Module example_suppressions
example_suppressions.py:1:0: C0114: Missing module docstring (missing-module-docstring)
example_suppressions.py:4:16: E0602: Undefined variable 'SomeAPIClient' (undefined-variable)
example_suppressions.py:12:11: W0718: Catching too general exception Exception (broad-exception-caught)
example_suppressions.py:10:13: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
example_suppressions.py:14:15: E0602: Undefined variable 'load_default_config' (undefined-variable)
example_suppressions.py:18:0: R0913: Too many arguments (6/5) (too-many-arguments)
example_suppressions.py:18:0: R0917: Too many positional arguments (6/5) (too-many-positional-arguments)
------------------------------------------------------------------
Your code has been rated at 0.00/10 (previous run: 0.00/10, +0.00)
Ignoring warnings on specific lines
Now let's fix the warnings that represent legitimate design choices rather than actual problems. Some of these warnings are real issues (like undefined variables), but others are intentional patterns we want to keep:
- The broad exception handling is intentional - we want to catch any config loading error and fall back to defaults
- The legacy function has many parameters because it's part of an existing API that can't be changed without breaking other code
- We'll leave the undefined variable errors since those would cause real crashes
import json
# Variable name that breaks naming conventions but is clearer
API_v2_client = SomeAPIClient()
def load_config_file(filename):
"""Load configuration file with broad exception handling."""
try:
with open(filename, 'r', encoding='utf-8') as f: # Fix the encoding warning
return json.load(f)
except Exception: # pylint: disable=broad-exception-caught
# We actually want to catch all exceptions here for safety
return load_default_config()
# Legacy function that can't be easily changed
def complex_calculation(a, b, c, d, e, f): # pylint: disable=too-many-arguments,too-many-positional-arguments
"""Old function with many parameters - changing it would break things."""
return (a + b) * (c + d) + (e * f)
Now run Pylint again to see how the suppressions work:
pylint example_suppressions.py
You'll see cleaner output with only the real issues remaining:
************* Module example_suppressions
example_suppressions.py:1:0: C0114: Missing module docstring (missing-module-docstring)
example_suppressions.py:4:16: E0602: Undefined variable 'SomeAPIClient' (undefined-variable)
example_suppressions.py:10:13: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)
example_suppressions.py:14:15: E0602: Undefined variable 'load_default_config' (undefined-variable)
------------------------------------------------------------------
Your code has been rated at 0.00/10 (previous run: 0.00/10, +0.00)
Notice how the specific warnings you disabled no longer appear, your code quality score improved from 0.00/10 to 4.00/10, and the real issues (undefined variables) are still flagged.
This shows the realistic progression and demonstrates that some warnings should be suppressed while others should be fixed.
Integrating Pylint with your development workflow
Effective code quality management requires integrating Pylint at multiple stages of your development process to catch issues early and maintain consistent standards.
Editor integration for real-time feedback
Modern code editors provide seamless Pylint integration for immediate feedback as you write code.
For Visual Studio Code, install the Python extension which includes Pylint support:
code --install-extension ms-python.python
Or you can install it through the VS Code interface by opening VS Code, clicking the Extensions icon in the sidebar (or pressing Ctrl+Shift+X
), searching for "pylint" in the extensions marketplace, and installing the official Python extension by Microsoft.
Configure Pylint as your preferred linter in VS Code settings:
{
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.linting.lintOnSave": true,
"python.linting.pylintArgs": [
"--rcfile=.pylintrc",
"--reports=no"
]
}
For other editors, Pylint integrates well with:
- PyCharm: Built-in support with configurable inspection profiles
- Vim/Neovim: Using plugins like
ale
or native LSP support - Sublime Text: Through the SublimeLinter-pylint package
- Emacs: Via flycheck or flymake integration
Automated quality checks with pre-commit hooks
Prevent problematic code from entering your repository by implementing Pylint as a pre-commit hook.
Initialize your project as a Git repository:
git init
Install pre-commit and configure it for your project:
pip install pre-commit
Create a comprehensive pre-commit configuration:
repos:
- repo: https://github.com/pycqa/pylint
rev: v3.3.7
hooks:
- id: pylint
args: [--rcfile=.pylintrc, --reports=no, --score=no]
additional_dependencies: [pylint-django, pylint-celery]
- repo: https://github.com/psf/black
rev: 24.10.0
hooks:
- id: black
language_version: python3
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
args: [--profile=black]
Install the pre-commit hooks:
pre-commit install
Now Pylint runs automatically before each commit, ensuring code quality standards are maintained:
git add .
git commit -m "Add Pylint configuration and sample code"
If Pylint finds issues, the commit will be blocked:
Final thoughts
Pylint helps you write cleaner, more reliable Python code by catching mistakes early and enforcing coding standards.
When you integrate it into your editor and Git workflow, you can maintain consistent code quality with minimal effort. Start with the most important issues and gradually improve your codebase. Pylint will quickly become a natural part of your development routine.
For comprehensive documentation and advanced configuration options, visit the official documentation.
Make your mark
Join the writer's program
Are you a developer and love writing and sharing your knowledge with the world? Join our guest writing program and get paid for writing amazing technical guides. We'll get them to the right readers that will appreciate them.
Write for us
Build on top of Better Stack
Write a script, app or project on top of Better Stack and share it with the world. Make a public repository and share it with us at our email.
community@betterstack.comor submit a pull request and help us build better products for everyone.
See the full list of amazing projects on github