Skip to main content

Pylint

pip install pylint
pylint your_code.py --fail-under=9 --enable=all --disable=missing-docstring
pylint app/
max-line-length=88
disable=
missing-docstring,
invalid-name
enable=
all

Einführung

Pylint ist ein statisches Code-Analyse-Tool, das Fehler in Python-Code findet, Coding-Standards durchsetzt und hilft, die Codequalität zu verbessern. Es bietet:

  • Syntax-Überprüfung
  • Einhaltung von Code-Standards (PEP 8)
  • Code-Smell-Erkennung
  • Refactoring-Vorschläge
  • Duplizierungserkennnung

Installation

# Standard-Installation
pip install pylint

# Mit Extras für bestimmte Frameworks
pip install pylint-django # Für Django-Projekte
pip install pylint-flask # Für Flask-Projekte

Grundlegende Verwendung

# Eine einzelne Datei analysieren
pylint my_file.py

# Ein ganzes Verzeichnis analysieren
pylint my_directory/

# Mehrere Dateien/Verzeichnisse analysieren
pylint file1.py file2.py directory/

# Mit bestimmter Bewertungsschwelle
pylint --fail-under=8 my_file.py

# Mit detailliertem Report
pylint --reports=y my_file.py

# Mit spezifischen Nachrichten aktivieren/deaktivieren
pylint --disable=C0111,W0611 --enable=W0611 my_file.py

Pylint-Konfigurationsdatei

Pylint kann über eine Konfigurationsdatei konfiguriert werden. Erstellen Sie eine der folgenden Dateien:

  • .pylintrc im Projekt-Stammverzeichnis
  • pylintrc im Projekt-Stammverzeichnis
  • ~/.pylintrc im Home-Verzeichnis
  • setup.cfg mit einer [pylint]-Sektion
# Konfigurationsdatei erstellen
pylint --generate-rcfile > .pylintrc

Beispiel für eine .pylintrc-Datei

[MASTER]
# Python-Versionen: Minimum Requirement
py-version = 3.8

# Zusätzliche Plugins, z.B. für Django
load-plugins=pylint_django

# Dateien oder Verzeichnisse ignorieren
ignore=CVS, .git, .venv, venv, migrations

[MESSAGES CONTROL]
# Deaktivieren bestimmter Warnungen
disable=
missing-docstring,
invalid-name,
too-many-arguments,
too-few-public-methods,
no-self-use,
duplicate-code

# Aktivieren bestimmter Warnungen
enable=
unused-import,
unused-variable

[FORMAT]
# Maximale Zeilenlänge
max-line-length=88

# String-Format prüfen (Formatierung mit %)
check-str-concat-over-line-jumps=no

[DESIGN]
# Maximale Anzahl von Argumenten für Funktionen/Methoden
max-args=5

# Maximale lokale Variablen
max-locals=15

# Maximale Return-Statements
max-returns=6

# Maximale Branches einer Funktion (if/else-Ketten)
max-branches=12

# Maximale Anzahl von Attributen für Klassen
max-attributes=7

# Maximale Anzahl von Public-Methods für Klassen
max-public-methods=20

[SIMILARITIES]
# Minimale Zeilenlänge für Duplikate
min-similarity-lines=4

# Kommentare ignorieren
ignore-comments=yes

# Dokumentations-Strings ignorieren
ignore-docstrings=yes

# Import-Anweisungen ignorieren
ignore-imports=yes

[TYPECHECK]
# Ignoriert Module, die problematisch beim Importieren sind
ignored-modules=numpy,torch,tensorflow

# Ignoriert Members, die problematisch beim Importieren sind
ignored-classes=numpy,torch,tensorflow

[BASIC]
# Regulärer Ausdruck für Variablennamen
variable-rgx=[a-z_][a-z0-9_]{0,30}$

# Regulärer Ausdruck für Funktionsnamen
function-rgx=[a-z_][a-z0-9_]{0,30}$

# Regulärer Ausdruck für Klassennamen
class-rgx=[A-Z_][a-zA-Z0-9]+$

# Regulärer Ausdruck für Konstantennamen
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$

Integration in Pre-commit Hooks

# .pre-commit-config.yaml
repos:
- repo: https://github.com/pycqa/pylint
rev: v2.17.0
hooks:
- id: pylint
args: [--rcfile=.pylintrc]

Integration in CI/CD-Pipelines

GitHub Actions

name: Pylint

on: [push, pull_request]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pylint
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Analyze code with pylint
run: |
pylint $(git ls-files '*.py') --fail-under=8

GitLab CI/CD

pylint:
stage: test
image: python:3.10
script:
- pip install pylint
- pip install -r requirements.txt
- pylint $(find . -name "*.py" | grep -v "venv/" | grep -v "migrations/") --fail-under=8
artifacts:
paths:
- pylint.log
when: always

Gängige Pylint-Fehlercodes und ihre Bedeutung

CodeKategorieBedeutung
C0103conventionInvalid name (zu kurz, entspricht nicht Konventionen)
C0111conventionMissing docstring (fehlende Dokumentation)
C0301conventionLine too long (Zeile überschreitet Längenbegrenzung)
E0001errorSyntax error (Syntaxfehler)
E0401errorImport error (Modul kann nicht importiert werden)
E1101errorNo member (Attribut/Methode existiert nicht)
R0201refactorMethod could be a function (Methode nutzt kein self)
R0903refactorToo few public methods (Klasse mit zu wenigen Methoden)
R0904refactorToo many public methods (zu viele öffentliche Methoden)
R0912refactorToo many branches (zu viele if-else-Zweige)
R0913refactorToo many arguments (zu viele Parameter)
R0914refactorToo many local variables (zu viele lokale Variablen)
R0915refactorToo many statements (zu viele Anweisungen)
W0102warningDangerous default value (mutable default argument)
W0611warningUnused import (importiertes Modul wird nicht genutzt)
W0612warningUnused variable (unbenutzte Variable)
W0613warningUnused argument (unbenutzter Parameter)
W1201warningUse % formatting in logging functions (falsche String-Formatierung)

Beispiel: Typische Pylint-Probleme und ihre Lösungen

Problem 1: Unbenutzte Imports (W0611)

# Schlecht
import os
import sys
import datetime

def get_current_date():
return datetime.datetime.now()
# Gut
import datetime

def get_current_date():
return datetime.datetime.now()

Problem 2: Zu viele Argumente (R0913)

# Schlecht
def process_user(name, age, email, address, city, country, phone, role):
# Verarbeitung...
pass
# Gut
class UserData:
def __init__(self, name, age, email, address, city, country, phone, role):
self.name = name
self.age = age
self.email = email
self.address = address
self.city = city
self.country = country
self.phone = phone
self.role = role

def process_user(user_data):
# Verarbeitung...
pass

Problem 3: Fehlende Docstrings (C0111)

# Schlecht
def calculate_total(items):
return sum(item.price for item in items)
# Gut
def calculate_total(items):
"""
Berechnet die Gesamtsumme aller Preise der übergebenen Elemente.

Args:
items: Eine Sammlung von Objekten mit einem price-Attribut.

Returns:
float: Die Summe aller Preise.
"""
return sum(item.price for item in items)

Best Practices für sauberen Python-Code mit Pylint

  1. Konsistenter Coding-Style:

    • Befolgen Sie PEP 8 für Namenskonventionen.
    • Setzen Sie eine konsistente maximale Zeilenlänge fest (z.B. 88 für Black).
  2. Aussagekräftige Namen:

    • Verwenden Sie beschreibende Namen für Variablen, Funktionen und Klassen.
    • Vermeiden Sie Ein-Buchstaben-Variablen außer in Schleifen oder als Zählvariablen.
  3. Ordentliche Dokumentation:

    • Fügen Sie Docstrings zu allen Funktionen, Klassen und Modulen hinzu.
    • Dokumentieren Sie Parameter, Rückgabewerte und Ausnahmen.
  4. Code-Struktur:

    • Begrenzen Sie die Anzahl der Argumente pro Funktion.
    • Vermeiden Sie tiefe Verschachtelungen von Kontrollstrukturen.
    • Halten Sie Funktionen und Klassen klein und fokussiert.
  5. Fehlerbehandlung:

    • Fangen Sie spezifische Ausnahmen statt allgemeiner Exception.
    • Verwenden Sie with-Blöcke für Ressourcenverwaltung.

Integration mit anderen Tools

Mit Black (Formatter)

# Installation
pip install black

# Ausführen
black --line-length=88 .

# Integration mit Pylint
# In .pylintrc:
[FORMAT]
max-line-length=88

Mit isort (Import-Sortierung)

# Installation
pip install isort

# Ausführen
isort .

# Konfiguration für Black-Kompatibilität in pyproject.toml
[tool.isort]
profile = "black"
line_length = 88

Mit mypy (Typprüfung)

# Installation
pip install mypy

# Ausführen
mypy .

# Konfiguration in pyproject.toml
[tool.mypy]
python_version = "3.10"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true

Beispiel für einen umfassenden Python-Qualitäts-Workflow

#!/bin/bash
# quality_check.sh

echo "Running isort..."
isort .

echo "Running black..."
black .

echo "Running mypy..."
mypy .

echo "Running pylint..."
pylint $(find . -name "*.py" -not -path "*/\.*" -not -path "*/venv/*")

echo "Running pytest with coverage..."
pytest --cov=./ --cov-report=xml

echo "Quality check completed!"