Der Weg zur Typüberprüfung von 4 Millionen Zeilen Python-Code. Teil 3

Wir präsentieren Ihnen den dritten Teil unserer Übersetzung des Materials über den Weg, den Dropbox bei der Implementierung eines Python-Code-Typprüfsystems gegangen ist.

Der Weg zur Typüberprüfung von 4 Millionen Zeilen Python-Code. Teil 3

→ Vorherige Teile: erster und zweiter

Erreichung von 4 Millionen Zeilen typisiertem Code

Eine weitere wichtige Aufgabe (dies war das zweithäufigste Anliegen in den internen Umfragen) war die Steigerung des Anteils des Dropbox-Codes, der Typprüfungen unterzogen wurde. Wir haben verschiedene Ansätze ausprobiert, um dieses Ziel zu erreichen – von einem natürlichen Wachstum der typisierten Codebasis bis hin zur Fokussierung der mypy-Teammitglieder auf statische und dynamische automatisierte Typinferenz. Letztendlich entstand der Eindruck, dass es keine einfache gewinnbringende Strategie gibt, aber wir konnten ein schnelles Wachstum des annotierten Codes erreichen, indem wir mehrere Ansätze kombiniert haben.

Durch unsere größte Python-Repository (mit Backend-Code) hat die Anzahl der annotierten Codezeilen fast 4 Millionen erreicht. Die Arbeiten zur statischen Typisierung des Codes wurden über etwa drei Jahre durchgeführt. Mypy unterstützt jetzt verschiedene Arten von Berichten zur Typabdeckung, die die Überwachung des Fortschritts der Typisierung erleichtern. Insbesondere können wir Berichte über Code mit Unsicherheiten in den Typen erstellen, wie z.B. die explizite Verwendung von Typen Any in Anmerkungen, die nicht überprüfbar sind, oder wie der Import von Drittanbieter-Bibliotheken, die keine Typannotationen enthalten. Im Rahmen des Projekts zur Verbesserung der Typüberprüfung bei Dropbox haben wir zur Verbesserung der Typdefinitionen (sog. Stub-Dateien) für einige beliebte Open-Source-Bibliotheken im zentralen Python-Repository beigetragen typeshed.

Wir haben neue Möglichkeiten des Typsystems implementiert (und in späteren PEPs standardisiert), die es ermöglichen, genauere Typen für bestimmte Python-Muster zu verwenden. Ein bemerkenswertes Beispiel dafür ist TypeDict, der Typen für JSON-ähnliche Wörterbücher bereitstellt, die eine feste Menge von String-Schlüsseln haben, wobei jeder einen eigenen Typwert hat. Wir werden unser Typensystem weiter ausbauen. Wahrscheinlich wird unser nächster Schritt die verbesserte Unterstützung der Python-Funktionen für den Umgang mit Zahlen sein.

Der Weg zur Typüberprüfung von 4 Millionen Zeilen Python-Code. Teil 3
Anzahl der annotierten Codezeilen: Server

Der Weg zur Typüberprüfung von 4 Millionen Zeilen Python-Code. Teil 3
Anzahl der annotierten Codezeilen: Client

Der Weg zur Typüberprüfung von 4 Millionen Zeilen Python-Code. Teil 3
Gesamtanzahl der annotierten Codezeilen

Hier ist eine Übersicht der wichtigsten Merkmale der Maßnahmen, die wir zur Erhöhung der annotierten Codezeilen in Dropbox ergriffen haben:

Strenge der Annotation. Wir haben die Anforderungen an die Strenge der Annotation neuen Codes schrittweise erhöht. Wir begannen mit Linter-Empfehlungen, die vorschlugen, Annotationen in Dateien hinzuzufügen, die bereits einige Annotationen enthalten. Jetzt verlangen wir, dass Typannotationen in neuen Python-Dateien und in den meisten bestehenden Dateien vorhanden sind.

Typisierungsberichte. Wir senden wöchentlich Berichte an die Teams über den Typisierungsgrad ihres Codes und geben Ratschläge dazu, was zuerst annotiert werden sollte.

Förderung von mypy. Wir berichten über mypy auf verschiedenen Veranstaltungen und stehen Teams zur Seite, um ihnen den Einstieg in die Typannotation zu erleichtern.

Umfragen. Wir führen regelmäßige Umfragen unter Nutzern durch, um die Hauptprobleme zu identifizieren. Wir sind bereit, weit zu gehen, um diese Herausforderungen anzugehen (sogar bis zur Schaffung einer neuen Sprache, um mypy zu beschleunigen!).

Leistungsverbesserung. Wir haben die Leistung von mypy erheblich verbessert, indem wir einen Daemon und mypyc verwenden. Dies wurde getan, um die Unannehmlichkeiten während des Annotationprozesses zu glätten und um die Bearbeitung großer Codebasen zu ermöglichen.

Integration mit Editoren. Wir haben Tools geschaffen, um die Ausführung von mypy in den bei Dropbox beliebten Editoren zu unterstützen. Dazu gehören PyCharm, Vim und VS Code. Dies hat den Prozess der Annotation und der Funktionsprüfung von Code erheblich vereinfacht. Solche Maßnahmen sind typischerweise beim Annotieren bestehender Codes erforderlich.

Statische Analyse. Wir haben ein Tool zur Extraktion von Funktionssignaturen mithilfe statischer Analyse entwickelt. Dieses Tool funktioniert am besten in relativ einfachen Situationen, hat uns jedoch geholfen, den Codeumfang mit Typen mühelos zu erweitern.

Unterstützung von Drittanbieterbibliotheken. In vielen unserer Projekte verwenden wir das SQLAlchemy-Toolset. Es nutzt die dynamischen Möglichkeiten von Python, die von PEP 484-Typen nicht direkt modelliert werden können. In Übereinstimmung mit PEP 561 haben wir eine passende Stub-Datei erstellt und ein Plugin für mypy (Open Source), das die Unterstützung für SQLAlchemy verbessert.

Herausforderungen, mit denen wir konfrontiert wurden

Der Weg zu 4 Millionen Zeilen typisierten Codes war nicht immer leicht. Auf diesem Weg sind wir auf zahlreiche Hürden gestoßen und haben einige Fehler gemacht. Hier sind einige der Probleme, mit denen wir konfrontiert waren. Wir hoffen, dass dieser Bericht anderen hilft, ähnliche Probleme zu vermeiden.

Übersehene Dateien. Wir haben mit der Überprüfung nur einer kleinen Menge an Dateien begonnen. Alles, was nicht zu diesen Dateien gehörte, wurde nicht überprüft. Dateien wurden zur Prüfungslist hinzugefügt, sobald die ersten Anmerkungen auftraten. Falls etwas aus einem Modul importiert wurde, das außerhalb des Prüfbereichs lag, handelte es sich um die Arbeit mit Werten vom Typ Any, die überhaupt nicht überprüft wurden. Dies führte zu einem erheblichen Verlust an Typgenauigkeit, insbesondere in den frühen Phasen der Migration. Diese Methode funktionierte jedoch erstaunlich gut, obwohl es typischerweise der Fall war, dass das Hinzufügen von Dateien zur Typprüfung Probleme in anderen Bereichen des Codes aufdeckte. Im schlimmsten Fall, wenn zwei isolierte Codeteile zusammengeführt wurden, in denen die Typen unabhängig voneinander bereits überprüft worden waren, stellte sich heraus, dass die Typen dieser Bereiche nicht miteinander kompatibel waren. Dies führte zu einer Reihe von erforderlichen Änderungen in den Annotationen. Wenn wir nun zurückblicken, erkennen wir, dass wir die grundlegenden Bibliotheksmodule frühzeitig in den Typprüfungsbereich von mypy aufnehmen sollten. Dies hätte unsere Arbeit wesentlich planbarer gemacht.

Annotation von altem Code. Als wir mit unserer Arbeit begannen, hatten wir etwa 4 Millionen Zeilen bereits bestehenden Python-Codes. Es war klar, dass die Annotation all dieses Codes keine leichte Aufgabe war. Daher entwickelten wir ein Werkzeug namens PyAnnotate, das zur Laufzeit während der Tests Typinformationen sammeln kann und in der Lage ist, Typspezifikationen basierend auf den gesammelten Informationen in den Code einzufügen. Allerdings haben wir keine umfassende Verbreitung dieses Werkzeugs festgestellt. Das Sammeln von Typinformationen war langsam, und die automatisch generierten Annotationen erforderten oft mehrere manuelle Anpassungen. Wir dachten darüber nach, dieses Werkzeug bei jeder Codeüberprüfung automatisch auszuführen oder Typinformationen basierend auf der Analyse einer bestimmten Menge echter Netzwerkaufrufe zu sammeln, entschieden uns jedoch dagegen, da jeder dieser Ansätze zu riskant war.

Zusammenfassend lässt sich sagen, dass der Großteil des Codes manuell von seinen Eigentümern annotiert wurde. Um diesen Prozess in die richtige Richtung zu lenken, erstellen wir Berichte über besonders wichtige Module und Funktionen, die annotiert werden müssen. So ist es beispielsweise wichtig, den bibliotheksmodul, der an vielen Stellen verwendet wird, mit Typannotations zu versehen. Im Gegensatz dazu ist es nicht mehr so wichtig, einen alten Dienst, der durch einen neuen ersetzt wird, zu annotieren. Darüber hinaus experimentieren wir mit dem Einsatz statischer Analysen, um Typannotations für alten Code zu generieren.

Zirkuläre Importe. Oben habe ich über zirkuläre Importe (die "Abhängigkeitsknäuel") gesprochen, deren Existenz die Beschleunigung von mypy erschwerte. Zudem mussten wir intensiv daran arbeiten, mypy mit Unterstützung für alle Arten von Idiomen auszustatten, die durch diese zirkulären Importe verursacht werden. Kürzlich haben wir ein umfassendes Redesign-Projekt abgeschlossen, das die meisten Probleme von mypy im Zusammenhang mit zirkulären Importen behoben hat. Diese Probleme stammen tatsächlich aus den sehr frühen Tagen des Projekts, noch aus Alore, der Programmiersprache, auf die mypy ursprünglich ausgerichtet war. Die Syntax von Alore ermöglicht es, Probleme mit zirkulären Importbefehlen leicht zu lösen. Das moderne mypy hat einige Einschränkungen von seiner frühen, einfachen Implementierung geerbt (die hervorragend für Alore geeignet war). Python macht die Arbeit mit zirkulären Importen hauptsächlich aufgrund der Mehrdeutigkeit von Ausdrücken komplizierter. Zum Beispiel kann während einer Zuweisungsoperation tatsächlich ein Typalias definiert werden. Mypy ist nicht immer in der Lage, solche Dinge zu erkennen, bis ein großer Teil des Importzyklus verarbeitet wurde. In Alore gab es solche Mehrdeutigkeiten nicht. Fehlentscheidungen, die in den frühen Entwicklungsphasen des Systems getroffen wurden, können einem Programmierer viele Jahre später unangenehme Überraschungen bereiten.

Zusammenfassung: Der Weg zu 5 Millionen Codezeilen und neuen Horizonten

Das Projekt mypy hat einen langen Weg zurückgelegt — von den frühen Prototypen bis hin zu einem System, das die Typen von Produktionscode mit einem Umfang von 4 Millionen Zeilen kontrolliert. Im Laufe der Entwicklung von mypy wurde die Typisierung in Python standardisiert. Heutzutage hat sich rund um die Typisierung von Python-Code ein starkes Ökosystem entwickelt. Darin finden sich Unterstützung für Bibliotheken, Hilfsmittel für IDEs und Editoren sowie mehrere Typsysteme, von denen jedes seine eigenen Vor- und Nachteile hat.

Obwohl die Typprüfung bei Dropbox bereits als selbstverständlich angesehen wird, bin ich überzeugt, dass wir uns noch in der Anfangsphase der Typisierung von Python-Code befinden. Ich denke, dass sich die Technologien zur Typüberprüfung weiterhin weiterentwickeln und verbessern werden.

Wenn Sie in Ihrem umfangreichen Python-Projekt noch keine Typprüfungen verwendet haben, ist jetzt der ideale Zeitpunkt, um auf statische Typisierung umzusteigen. Ich habe mit einigen gesprochen, die diesen Schritt gemacht haben, und niemand bereut es. Die Typkontrolle verwandelt Python in eine Sprache, die viel besser für die Entwicklung großer Projekte geeignet ist als „herkömmliches Python“.

Sehr geehrte Leser! Nutzen Sie die Typkontrolle in Ihren Python-Projekten?

Der Weg zur Typüberprüfung von 4 Millionen Zeilen Python-Code. Teil 3
Der Weg zur Typüberprüfung von 4 Millionen Zeilen Python-Code. Teil 3

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster