Pylint von innen nach außen. Wie macht er das?

Verschiedene Helfer beim Schreiben von coolem Code umgeben uns, Linter, Typekchera, Dienstprogramm zum Auffinden von Schwachstellen, alle bei uns. Wir sind daran gewöhnt und verwenden es, ohne auf Details wie eine „Black Box“ einzugehen. Zum Beispiel verstehen nur wenige Menschen die Prinzipien von Pylint, einem solchen unverzichtbaren Werkzeug zur Optimierung und Verbesserung von Python-Code.

Aber Maxim Mazaev weiß, wie wichtig es ist, seine Werkzeuge zu verstehen, und er sagte es uns bei Moscow Python Conf ++ . Anhand von Beispielen aus der Praxis zeigte er, wie das Wissen über das interne Gerät und die Plug-Ins von Pylint dazu beitrug, die Codeüberprüfungszeit zu verkürzen, die Codequalität zu verbessern und die Entwicklungseffizienz im Allgemeinen zu verbessern. Unten finden Sie eine Entschlüsselungsanweisung.



Warum brauchen wir Pylint?


Wenn Sie es bereits verwenden, kann sich die Frage stellen: "Warum wissen, was in Pylint enthalten ist, wie kann dieses Wissen helfen?"

In der Regel schreiben Entwickler Code, starten den Linter, erhalten Nachrichten darüber, was verbessert werden soll, wie der Code schöner wird, und nehmen die vorgeschlagenen Änderungen vor. Jetzt ist der Code einfacher zu lesen und schämt sich nicht, Kollegen zu zeigen.

Lange Zeit arbeiteten sie mit Pylint im Cyan-Institut genauso, mit geringfügigen Ergänzungen: Sie änderten die Konfigurationen, entfernten unnötige Regeln und erhöhten die maximale Zeichenfolgenlänge.

Aber irgendwann stießen sie auf ein Problem, für das ich mich tief in Pylint vertiefen und herausfinden musste, wie es funktioniert. Was ist dieses Problem und wie kann man es lösen? Lesen Sie weiter.


Über den Sprecher: Maxim Mazaev ( Backslash ), 5 Jahre in der Entwicklung, arbeitet bei CIAN. Lernt Python, Asynchronität und funktionale Programmierung.

Über Cyan


Die meisten glauben, dass CIAN eine Immobilienagentur mit Maklern ist und sind sehr überrascht, als sie herausfinden, dass wir anstelle von Maklern Programmierer haben.

Wir sind ein technisches Unternehmen, in dem es keine Makler gibt, aber viele Programmierer.

  • 1 Million Unique User pro Tag.
  • Das größte Bulletin Board für den Verkauf und die Vermietung von Immobilien in Moskau und St. Petersburg. 2018 traten sie in die Bundesebene ein und arbeiteten in ganz Russland.
  • Fast 100 Mitarbeiter im Entwicklungsteam, von denen 30 täglich Python-Code schreiben.

Jeden Tag werden Hunderte und Tausende neuer Codezeilen produziert. Die Anforderungen an den Code sind ziemlich einfach:

  • Code von anständiger Qualität.
  • Stilistische Homogenität. Alle Entwickler sollten ungefähr ähnlichen Code ohne "Vinaigrette" in Repositorys schreiben.

Um dies zu erreichen, benötigen Sie natürlich eine Codeüberprüfung.

Codeüberprüfung


Die Codeüberprüfung in CIAN erfolgt in zwei Schritten:

  1. Die erste Stufe ist automatisiert . Der Jenkins-Roboter führt die Tests aus, führt Pylint aus und überprüft die Konsistenz der API zwischen Microservices, da wir Microservices verwenden. Wenn zu diesem Zeitpunkt die Tests fehlschlagen oder der Linter etwas Seltsames anzeigt, ist dies eine Gelegenheit, die Pull-Anforderung abzulehnen und den Code zur Überarbeitung zu senden.
  2. Wenn die erste Phase erfolgreich war, kommt die zweite - die Genehmigung von zwei Entwicklern . Sie können bewerten, wie gut der Code in Bezug auf die Geschäftslogik ist, eine Pull-Anforderung genehmigen oder den Code zur Überarbeitung zurückgeben.


Probleme bei der Codeüberprüfung


Die Pull-Anforderung besteht möglicherweise die Codeüberprüfung nicht, weil:

  • Fehler in der Geschäftslogik, wenn ein Entwickler ein Problem ineffektiv oder falsch gelöst hat;
  • Probleme mit dem Codestil.

Was könnten die Stilprobleme sein, wenn der Linter den Code überprüft?

Jeder, der in Python schreibt, weiß, dass es eine Anleitung zum Schreiben von PEP-8- Code gibt. Wie jeder Standard ist PEP-8 ziemlich allgemein und für uns als Entwickler ist dies nicht genug. Ich möchte den Standard an einigen Stellen spezifizieren und an anderen erweitern.

Aus diesem Grund haben wir unsere internen Vorkehrungen getroffen, wie der Code aussehen und funktionieren soll, und sie als "Cian-Vorschläge ablehnen" bezeichnet .



"Cian-Vorschläge ablehnen" - eine Reihe von Regeln, jetzt gibt es ungefähr 15. Jede dieser Regeln ist die Grundlage dafür, dass die Pull-Anforderung abgelehnt und zur Überarbeitung gesendet wird.

Was behindert eine produktive Codeüberprüfung?


Es gibt ein Problem mit unseren internen Regeln - der Linter weiß nichts über sie, und es wäre seltsam, wenn er es wüsste - sie sind intern.
Der Entwickler, der die Aufgabe ausführt, muss sich immer an die Regeln erinnern und diese beachten. Wenn er eine der Regeln vergisst, weisen die Prüfer bei der Codeüberprüfung auf das Problem hin, die Aufgabe wird überarbeitet und die Freigabezeit der Aufgabe erhöht sich. Nach Abschluss und Korrektur von Fehlern müssen sich die Tester merken, was in der Aufgabe enthalten war, um den Kontext zu wechseln.

Dies schafft ein Problem sowohl für den Entwickler als auch für die Prüfer. Infolgedessen wird die Geschwindigkeit der Codeüberprüfung erheblich reduziert. Anstatt die Logik des Codes zu analysieren, beginnen die Tester, den visuellen Stil zu analysieren, dh sie führen die Arbeit des Linter aus: Sie scannen den Code zeilenweise und suchen nach Inkonsistenzen in der Einrückung im Importformat.

Wir möchten dieses Problem beseitigen.

Aber schreiben Sie uns nicht Ihren Linter?


Es scheint, dass das Problem durch ein Tool gelöst wird, das alle internen Vereinbarungen kennt und in der Lage ist, den Code auf ihre Implementierung zu überprüfen. Also brauchen wir unseren eigenen Linter?

Nicht wirklich. Die Idee ist dumm, weil wir bereits Pylint verwenden. Dies ist ein praktischer Linter, der von Entwicklern gemocht wird und in alle Prozesse integriert ist: Er läuft in Jenkins, generiert schöne Berichte, die vollständig zufrieden sind und in Form von Kommentaren auf Anfrage eingehen. Alles ist in Ordnung, ein zweiter Linter wird nicht benötigt .

Wie kann man das Problem lösen, wenn wir keinen eigenen Linter schreiben wollen?

Schreiben Sie ein Pylint Plugin


Sie können Plugins für Pylint schreiben, die als Checker bezeichnet werden. Unter jeder internen Regel können Sie Ihren eigenen Prüfer schreiben, der ihn prüft.

Betrachten Sie zwei Beispiele für solche Prüfer.

Beispiel Nr. 1


Irgendwann stellte sich heraus, dass der Code viele Kommentare der Form „TODO“ enthält - verspricht, ihn umzugestalten, unnötigen Code zu löschen oder ihn wunderschön umzuschreiben, aber nicht jetzt, sondern später. Es gibt ein Problem mit solchen Kommentaren - sie verpflichten Sie absolut zu nichts.

Das Problem


Der Entwickler schrieb ein Versprechen, atmete aus und ging beruhigt, um die nächste Aufgabe zu erledigen.


Zusammenfassend:

  • Kommentare mit Versprechungen hängen über die Jahre und werden nicht befolgt;
  • Code ist verschmutzt;
  • Die technischen Schulden häufen sich seit Jahren.

Zum Beispiel hat ein Entwickler vor 3 Jahren versprochen, nach einer erfolgreichen Veröffentlichung etwas zu entfernen, aber ist die Veröffentlichung in 3 Jahren erfolgt? Vielleicht ja. Soll ich in diesem Fall den Code löschen? Dies ist eine große Frage, aber höchstwahrscheinlich nicht.

Lösung: Schreiben Sie Ihren Checker für Pylint


Sie können Entwicklern nicht verbieten, solche Kommentare zu schreiben, aber Sie können sie dazu bringen, zusätzliche Arbeit zu leisten: Erstellen Sie im Tracker eine Aufgabe, um das Versprechen abzuschließen. Dann werden wir sie definitiv nicht vergessen.

Wir müssen alle Kommentare des Formulars TODO finden und sicherstellen, dass jeder von ihnen einen Link zu einer Aufgabe in Jira hat. Lass uns schreiben.

Was ist ein Checker in Bezug auf Pylint? Dies ist eine Klasse, die von der Basisklasse des Prüfers erbt und eine bestimmte Schnittstelle implementiert.

class TodoIssueChecker(BaseChecker): _ _implements_ _ = IRawChecker 

In unserem Fall ist dies IRawChecker - der sogenannte "rohe" Checker.

Ein Raw Checker durchläuft die Zeilen einer Datei und kann eine bestimmte Aktion für eine Zeile ausführen. In unserem Fall sucht der Prüfer in jeder Zeile nach etwas ähnlichem wie einem Kommentar und einem Link zu einer Aufgabe.

Für den Checker müssen Sie die Liste der Nachrichten ermitteln, die ausgegeben werden:

 msgs = { '9999': ('  TODO    ', issue-code-in-todo', ' ')} 

Die Nachricht hat:

  • die Beschreibung ist kurz und lang;
  • Checker-Code und ein kurzer mnemonischer Name, der bestimmt, um welche Art von Nachricht es sich handelt.

Der Nachrichtencode hat die Form "C1234", in der:

  • Der erste Buchstabe ist für verschiedene Arten von Nachrichten klar standardisiert: [C] Erfindung; [W] Arning; [E] Yog; [F] atal; [R] efactoring. Dank des Schreibens zeigt der Bericht sofort, was passiert: eine Erinnerung an die Vereinbarungen oder schwerwiegenden Probleme, die dringend angegangen werden müssen.
  • 4 Zufallszahlen, die nur für Pylint gelten.

Der Code wird benötigt, um die Prüfung zu deaktivieren, wenn sie nicht mehr benötigt wird. Sie können Pylint: disable und einen kurzen alphanumerischen Code oder einen mnemonischen Namen schreiben:

 # Pylint: disable=C9999 # Pylint: disable=issue-code-in-todo 

Die Autoren von Pylint empfehlen, den alphanumerischen Code aufzugeben und die Mnemonik zu verwenden, sie ist visueller.

Der nächste Schritt besteht darin, eine Methode namens process_module zu definieren.



Der Name ist sehr wichtig. Die Methode sollte so aufgerufen werden, da Pylint sie dann aufruft.

Der Knotenparameter wird an das Modul übergeben. In diesem Fall spielt es keine Rolle, was es ist oder um welchen Typ es sich handelt. Es ist nur wichtig, sich daran zu erinnern, dass der Knoten über eine Stream- Methode verfügt, die eine Datei zeilenweise zurückgibt.

Sie können die Datei durchgehen und für jede Zeile nach Kommentaren und Links zur Aufgabe suchen. Wenn es einen Kommentar, aber keinen Link gibt, geben Sie eine Warnung des Formulars 'Issue-Code-in-ToDo' mit dem Prüfcode und der Zeilennummer aus. Der Algorithmus ist recht einfach.

Registrieren Sie den Checker, damit Pylint davon erfährt. Dies erfolgt durch die Registerfunktion :

 def register(linter: Pylinter) -> None: linter. register_checker ( TodoIssueChecker(linter) ) 

  • Eine Instanz von Pylint kommt in die Funktion.
  • Es ruft die Methode register_checker auf.
  • Wir übergeben den Checker an die Methode.

Ein wichtiger Punkt: Das Prüfmodul muss sich in PYTHONPATH befinden, damit Pylint es später importieren kann.

Ein registrierter Prüfer wird durch eine Testdatei mit Kommentaren ohne Links zu Aufgaben überprüft.

 $ cat work. # T0D0:   , -! $ pylint work. --load-plugins todo_checker … 

Führen Sie für den Test Pylint aus, übergeben Sie das Modul an ihn, übergeben Sie den Prüfer mit dem Parameter load-plugins , und führen Sie im Linter zwei Phasen aus.

Phase 1. Plugin-Initialisierung


  • Alle Module mit Plugins werden importiert. Pylint hat interne und externe Prüfer. Sie kommen alle zusammen und werden importiert.
  • Wir registrieren - module.register (self) . Für jeden Prüfer wird die Registerfunktion aufgerufen, in der die Pylint-Instanz übergeben wird.
  • Es werden Überprüfungen durchgeführt: auf die Gültigkeit der Parameter, auf das Vorhandensein von Nachrichten, Optionen und Berichten im richtigen Format.

Phase 2. Analysieren Sie den Pool der Kontrolleure


Nach Phase 1 bleibt eine ganze Liste verschiedener Arten von Prüfern übrig:

  • AST-Prüfer;
  • Rohprüfer;
  • Token Checker.



Aus der Liste wählen wir diejenigen aus, die sich auf die Raw-Checker-Schnittstelle beziehen: Wir schauen uns an, welche Checker die IRawChecker-Schnittstelle implementieren, und nehmen sie für uns.

Rufen Sie für jeden ausgewählten Prüfer die Methode checker.process_module (Modul) auf und führen Sie die Prüfung aus.

Ergebnis


Führen Sie den Checker für die Testdatei erneut aus:

 $ cat work. # T0D0:   , -! $ pylint work,  --load-plugins todo_checker : 0,0:   T0D0     (issue-code-in-todo) 

Es wird eine Meldung angezeigt, die besagt, dass ein Kommentar zu TODO und kein Link zur Aufgabe vorhanden ist.

Das Problem ist gelöst, und jetzt müssen Entwickler bei der Codeüberprüfung den Code nicht mehr mit den Augen scannen, keine Kommentare finden, den Code-Autor daran erinnern, dass eine Vereinbarung besteht, und es ist ratsam, einen Link zu hinterlassen. Alles geschieht automatisch und die Codeüberprüfung ist etwas schneller.

Beispiel Nr. 2. Schlüsselwortargumente


Es gibt Funktionen, die Positionsargumente annehmen. Wenn es viele Argumente gibt, ist beim Aufrufen der Funktion nicht klar, wo sich das Argument befindet und warum es benötigt wird.

Das Problem


Zum Beispiel haben wir eine Funktion:

 get_offer_by_cian_id( "sale", rue, 859483, ) 

Der Code hat Verkauf und Wahr, und es ist unklar, was sie bedeuten. Es ist viel praktischer, wenn Funktionen mit vielen Argumenten nur mit benannten Argumenten aufgerufen werden:

 get_offer_by_cian_id( deal_type="sale", truncate=True, cian_id=859483, ) 

Dies ist ein guter Code, in dem sofort klar ist, wo sich der Parameter befindet, und wir werden ihre Reihenfolge nicht verwechseln. Versuchen wir, einen Prüfer zu schreiben, der solche Fälle prüft.

Der im vorherigen Beispiel verwendete "rohe" Prüfer ist für einen solchen Fall sehr schwer zu schreiben. Sie können superkomplexe reguläre Ausdrücke hinzufügen, aber dieser Code ist schwer zu lesen. Es ist gut, dass Pylint es ermöglicht, einen anderen Prüfertyp basierend auf dem abstrakten AST- Syntaxbaum zu schreiben, und wir werden ihn verwenden.

Text über AST


Ein AST- oder abstrakter Syntaxbaum ist eine Baumdarstellung des Codes, wobei der Scheitelpunkt die Operanden und die Blätter Operatoren sind.

Beispielsweise wird ein Funktionsaufruf, bei dem es ein Positionsargument und zwei benannte Argumente gibt, in einen abstrakten Baum umgewandelt:


Es gibt einen Scheitelpunkt vom Typ Call und er hat:

  • Funktionsattribute namens func;
  • eine Liste von Positionsargumenten args, wobei es einen Knoten mit dem Typ Const und einem Wert von 112 gibt;
  • Liste der benannten Argumente Schlüsselwörter.

Die Aufgabe in diesem Fall:

  • Suchen Sie im Modul alle Knoten vom Typ Call (Funktionsaufruf).
  • Berechnen Sie die Gesamtzahl der Argumente, die die Funktion akzeptiert.
  • Wenn mehr als 2 Argumente vorhanden sind, stellen Sie sicher, dass der Knoten keine Positionsargumente enthält.
  • Wenn es Positionsargumente gibt, zeigen Sie eine Warnung an.


 ll( func=Name(name='get_offer'), args=[Const(value=1298880)], keywords=[ … ]))] 

Aus Sicht von Pylint ist ein AST-basierter Prüfer eine Klasse, die von der Basisprüferklasse erbt und die IAstroidChecker- Schnittstelle implementiert:

 class NonKeywordArgsChecker(BaseChecker): -_ _implements_ _ = IAstroidChecker 

Wie im ersten Beispiel werden die Prüferbeschreibung, der Nachrichtencode und der kurze Mnemonenname in der Nachrichtenliste angegeben:

 msgs = { '9191': (' ', keyword-only-args', ' ')} 

Der nächste Schritt besteht darin, die visit_call- Methode zu definieren:

 def visit_call(self, node: Call) 

Die Methode muss nicht so genannt werden. Das Wichtigste dabei ist das Präfix visit_, und dann kommt der Name des Scheitelpunkts, der uns interessiert, mit einem kleinen Buchstaben.

  • Der AST-Parser geht durch den Baum und prüft für jeden Scheitelpunkt, ob für checkr die Schnittstelle visit_ <Name> definiert ist.
  • Wenn ja, dann nenne es.
  • Rekursiv geht durch alle ihre Kinder.
  • Beim Verlassen eines Knotens wird die Methode Leave_ <Name> aufgerufen.

In diesem Beispiel empfängt die visit_call-Methode einen Knoten vom Typ Aufruf als Eingabe und prüft, ob mehr als zwei Argumente vorhanden sind und ob Positionsargumente vorhanden sind, um eine Warnung auszulösen und den Code an den Knoten selbst zu übergeben.

 def visit_call(self, n): if node.args and len(node.args + node.keywords) > 2: self.add_message( 'keyword-only-args', node=node ) 

Wir registrieren den Checker wie im vorherigen Beispiel: Wir übertragen die Pylint-Instanz, rufen register_checker auf, übergeben den Checker selbst und starten ihn.

 def register(linter: Pylinter) -> None: linter.register_checker( TodoIssueChecker(linter) ) 

Dies ist ein Beispiel für einen Testfunktionsaufruf, bei dem drei Argumente vorhanden sind und nur eines davon benannt ist:

 $ cat work. get_offers(1, True, deal_type="sale") $ Pylint work.py --load-plugins non_kwargs_checker … 

Dies ist eine Funktion, die aus unserer Sicht möglicherweise falsch aufgerufen wird. Starten Sie Pylint.

Die Plugin-Initialisierungsphase 1 wird wie im vorherigen Beispiel vollständig wiederholt.

Phase 2. Modulanalyse bei AST


Der Code wird in einen AST-Baum analysiert. Die Analyse wird von der Astroid-Bibliothek durchgeführt .

Warum Astroid, nicht AST (stdlib)


Astroid verwendet intern nicht das Standard-Python-AST-Modul, sondern den typisierten AST-Parser typed_ast , der dadurch gekennzeichnet ist, dass er die PEP 484- Typhinweise unterstützt . Typed_ast ist ein Zweig von AST, einer Verzweigung, die sich parallel entwickelt. Interessanterweise gibt es dieselben Fehler in AST, die parallel behoben werden.

 from module import Entity def foo(bar): # type: (Entity) -> None return 

Zuvor verwendete Astroid das Standard-AST-Modul, bei dem das Problem auftreten konnte, die in den im zweiten Python verwendeten Kommentaren definierten Taiphints zu verwenden. Wenn Sie diesen Code über Pylint überprüfen, schwört er bis zu einem bestimmten Punkt auf nicht verwendeten Import, da die importierte Entitätsklasse nur im Kommentar vorhanden ist.

Irgendwann kam Guido Van Rossum auf GitHub zu Astroid und sagte: „Leute, Sie haben Pylint, was in solchen Fällen schwört, und wir haben einen typisierten AST-Parser, der all dies unterstützt. Lass uns Freunde sein!"

Die Arbeit hat begonnen zu kochen! 2 Jahre vergingen, in diesem Frühjahr wechselte Pylint zu einem typisierten AST-Parser und hörte auf, auf solche Dinge zu schwören. Importe für Taiphints werden nicht mehr als unbenutzt markiert.

Astroid verwendet einen AST-Parser, um den Code in einen Baum zu analysieren, und führt dann beim Erstellen einige interessante Dinge aus. Wenn Sie beispielsweise import * verwenden , wird alles mit einem Sternchen importiert und den Einheimischen hinzugefügt, um Fehler bei nicht verwendeten Importen zu vermeiden.

Transformations-Plugins werden in Fällen verwendet, in denen es einige komplexe Modelle gibt, die auf Metaklassen basieren, wenn alle Attribute dynamisch generiert werden. In diesem Fall ist Astroid sehr schwer zu verstehen, was gemeint ist. Bei der Überprüfung schwört Pylint, dass die Modelle beim Zugriff nicht über ein solches Attribut verfügen. Mit den Transform-Plugins können Sie das Problem lösen:

  • Helfen Sie Astroid, den abstrakten Baum zu ändern und die Dynamik von Python zu verstehen.
  • Ergänzen Sie AST mit nützlichen Informationen.

Ein typisches Beispiel ist Pylint-Django . Bei der Arbeit mit komplexen Django-Modellen schwört der Linter häufig auf unbekannte Eigenschaften. Pylint-Django löst gerade dieses Problem.

Phase 3. Analysieren Sie den Pool der Kontrolleure


Wir kehren zum Checker zurück. Wir haben wieder eine Liste von Prüfern, aus denen wir diejenigen finden, die die AST-Prüferschnittstelle implementieren.

Phase 4. Analysieren Sie die Prüfer nach Knotentypen


Als nächstes finden wir Methoden für jeden Prüfer. Es gibt zwei Arten von Methoden:

  • visit_ <Knotenname>
  • lev_ <Knotenname>.

Es wäre schön zu wissen, welche Knoten Sie für einen Knoten aufrufen müssen, während Sie in einem Baum gehen. Daher verstehen sie das Wörterbuch, wobei der Schlüssel der Name des Knotens ist. Der Wert ist eine Liste der Prüfer, die an der Tatsache des Zugriffs auf diesen Knoten interessiert sind.

 _visit_methods = dict( < > : [checker1, checker2 ... checkerN] ) 

Das gleiche gilt für Leave-Methoden: Ein Schlüssel in Form eines Knotennamens, eine Liste von Prüfern, die an der Tatsache interessiert sind, dass dieser Knoten verlassen wird.

 _leave_methods = dict( < >: [checker1, checker2 ... checkerN] ) 

Starten Sie Pylint. Es wird eine Warnung angezeigt, dass wir eine Funktion haben, bei der mehr als zwei Argumente und ein Positionsargument enthalten sind:

 $ cat work. get_offers(1, True, deal_type="sale") $ Pylint work.py --load-plugins non_kwargs_checker C: 0, 0:  c >2      (keyword-only-args) 

Das Problem ist gelöst. Jetzt müssen Programmierer für die Codeüberprüfung die Argumente der Funktion nicht mehr lesen, der Linter erledigt dies für sie. Wir haben Zeit gespart , Zeit für die Codeüberprüfung und Aufgaben in der Produktion schneller erledigt.

Und um Tests zu schreiben?


Mit Pylint können Sie Unit-Tests von Checkern durchführen, und das ist sehr einfach. Aus Sicht des Linter sieht der Test-Checker wie eine Klasse aus, die vom abstrakten CheckerTestCase erbt. Es muss der Prüfer angegeben werden, der darin geprüft wird.

 class TestNonKwArgsChecker(CheckerTestCase): CHECKER_CLASS = NonKeywordArgsChecker 

Schritt 1. Wir erstellen einen Test-AST-Knoten aus dem Teil des Codes, den wir überprüfen.

 node = astroid.extract_node( "get_offers(3, 'magic', 'args')" ) 

Schritt 2. Stellen Sie sicher, dass der Prüfer, der den Knoten betritt, die entsprechende Nachricht entweder auslöst oder nicht:

 with self.assertAddsMessages(message): self.checker.visit_call(node) 

Tokenchecker


Es gibt eine andere Art von Prüfer namens TokenChecker . Es funktioniert nach dem Prinzip eines lexikalischen Analysators. Python verfügt über ein Tokenize- Modul, das die Arbeit eines lexikalischen Scanners erledigt und den Code in eine Liste von Token aufteilt. Es könnte ungefähr so ​​aussehen:


Variablennamen, Funktionsnamen und Schlüsselwörter werden zu Token vom Typ NAME, und Trennzeichen, Klammern und Doppelpunkte werden zu Token vom Typ OP. Darüber hinaus gibt es separate Token für Einrückung, Zeilenvorschub und umgekehrte Übersetzung.

So funktioniert Pylint mit TokenChecker:

  • Das zu testende Modul ist mit einem Token versehen.
  • Eine große Liste von Token wird an alle Prüfer übergeben, die ITokenChecker implementieren, und die Methode process_tokens (Token) wird aufgerufen .

Wir haben die Verwendung von TokenChecker nicht gefunden, aber es gibt einige Beispiele, die Pylint verwendet:

  • Rechtschreibprüfung . Sie können beispielsweise alle Token mit Text eingeben und sich die lexikalische Kompetenz ansehen, Wörter aus Stoppwortlisten überprüfen usw.
  • Überprüfen Sie Einrückungen und Leerzeichen.
  • Arbeite mit Strings . Sie können beispielsweise überprüfen, ob Python 3 keine Unicode-Literale verwendet, oder sicherstellen, dass nur ASCI-Zeichen in der Byte-Zeichenfolge vorhanden sind.

Schlussfolgerungen


Wir hatten ein Problem mit der Codeüberprüfung. Die Entwickler führten die Arbeit des Linter durch, verbrachten ihre Zeit mit sinnlosem Scannen von Code und informierten den Autor über Fehler. Mit Pylint haben wir:

  • Routineprüfungen an den Linter übertragen, darin interne Vereinbarungen umgesetzt.
  • Erhöhte Überprüfung des Geschwindigkeits- und Qualitätscodes.
  • Die Anzahl der abgelehnten Pull-Anforderungen wurde reduziert, und die Zeit für das Übergeben von Aufgaben in der Produktion wurde verkürzt.

Ein einfacher Checker wird in einer halben Stunde geschrieben, ein komplexer in wenigen Stunden. Der Checker spart viel mehr Zeit als zum Schreiben benötigt und kämpft gegen mehrere nicht abgelehnte Pull-Anfragen.

Weitere Informationen zu Pylint und zum Schreiben von Checkern finden Sie in der offiziellen Dokumentation . In Bezug auf das Schreiben von Checkern ist dies jedoch eher schlecht. Zum Beispiel gibt es über TokenChecker nur eine Erwähnung, aber nicht darüber, wie der Checker selbst geschrieben wird. Weitere Informationen finden Sie in den Pylint-Quellen auf GitHub . Sie können sehen, welche Steine ​​im Standardpaket enthalten sind, und sich inspirieren lassen, Ihre eigenen zu schreiben.

Die Kenntnis des internen Designs von Pylint spart Arbeitsstunden und vereinfacht dies
Leistung und verbessert den Code. Sparen Sie Zeit, schreiben Sie guten Code und
Linter verwenden.
Die nächste Moskauer Python Conf ++ Konferenz findet am 5. April 2019 statt und Sie können bereits jetzt ein Frühbucherticket buchen. Es ist sogar noch besser, Ihre Gedanken zu sammeln und einen Bericht zu beantragen . Dann ist der Besuch kostenlos und schöne Brötchen werden als Bonus angeboten, einschließlich Coaching bei der Erstellung des Berichts.

Unsere Konferenz ist eine Plattform für Treffen mit Gleichgesinnten, Branchen-Engines, um Dinge zu kommunizieren und zu diskutieren, die Python-Entwickler lieben: Backend und Web, Datenerfassung und -verarbeitung, AI / ML, Testen, IoT. Wie es im Herbst gelaufen ist, schauen Sie sich den Videobericht auf unserem Python-Kanal an und abonnieren Sie den Kanal - bald werden wir die besten Berichte der Konferenz für den freien Zugang veröffentlichen.

Source: https://habr.com/ru/post/de433474/


All Articles