Wij presenteren u het derde deel van de vertaling van het materiaal over de weg die het bedrijf Dropbox heeft afgelegd bij de implementatie van een type-checking systeem voor Python-code.
ā Eerdere delen: en
Bereiken van 4 miljoen regels getypeerde code
Een andere belangrijke taak (dit was het op ƩƩn na populairste probleem dat deelnemers in interne enquĆŖtes bezighield) was het vergroten van de hoeveelheid code in Dropbox die gedekt was door type-checks. We hebben verschillende benaderingen uitgeprobeerd om dit probleem op te lossen ā van de natuurlijke groei van de getypeerde codebasis tot het concentreren van de inspanningen van het mypy-team op statische en dynamische automatische type-inferentie. Uiteindelijk leek er geen eenvoudige winnende strategie te zijn, maar we konden een snelle groei van de geannoteerde code bereiken door een mix van benaderingen.
Als resultaat is het aantal regels geannoteerde code in onze grootste Python-repository (met backend-code) bijna 4 miljoen bereikt. Het werk aan statische type-annotatie is ongeveer drie jaar geleden. Mypy ondersteunt nu verschillende soorten rapporten over de dekking van code door types, die het gemakkelijker maken om de voortgang van de type-inferentie te volgen. We kunnen bijvoorbeeld rapporten genereren voor code met onzekere types, zoals expliciet gebruik van types Any in annotaties die niet kunnen worden gecontroleerd, of voor imports van externe bibliotheken zonder type-annotaties. In het kader van ons project voor het verbeteren van de nauwkeurigheid van type-checking in Dropbox, hebben we bijgedragen aan de verbetering van type-definities (de zogenaamde stub-bestanden) voor enkele populaire open-source bibliotheken in de gecentraliseerde Python-repository .
We hebben (en gestandaardiseerd in latere PEP's) nieuwe mogelijkheden voor het typesysteem geĆÆmplementeerd die het mogelijk maken om nauwkeurigere types te gebruiken voor bepaalde specifieke Python-patronen. Een opvallend voorbeeld hiervan is TypeDict, dat types biedt voor JSON-achtige dictionaries met een vaste set van string-sleutels, elk met een waarde van hun eigen type. We zullen het typesysteem blijven uitbreiden. Waarschijnlijk is onze volgende stap het verbeteren van de ondersteuning voor de mogelijkheden van Python met betrekking tot getallen.

Aantal regels geannoteerde code: server

Aantal regels van geannoteerde code: klant

Totaal aantal regels van geannoteerde code
Hier is een overzicht van de belangrijkste kenmerken van de acties die we hebben ondernomen om de hoeveelheid geannoteerde code in Dropbox te verhogen:
Striktheid van annotatie. We hebben de vereisten voor de striktheid van de annotatie van nieuwe code geleidelijk verhoogd. We zijn begonnen met aanbevelingen van de linter, die voorstelden om annotaties toe te voegen aan bestanden waar al enkele annotaties aanwezig zijn. Nu vereisen we dat type-annotaties aanwezig zijn in nieuwe Python-bestanden en in de meeste bestaande bestanden.
Type-er rapporten. We versturen wekelijks rapporten aan de teams over het type-niveau van hun code en geven advies over wat als eerste geannoteerd moet worden.
Popularisering van mypy. We presenteren mypy op verschillende evenementen en communiceren met teams om hen te helpen met type-annotaties aan de slag te gaan.
Enquêtes. We voeren periodieke enquêtes onder gebruikers uit om de belangrijkste problemen te identificeren. We zijn bereid ver te gaan in het oplossen van deze problemen (zelfs tot het creëren van een nieuwe taal om mypy te versnellen!).
Prestaties. We hebben de prestaties van mypy aanzienlijk verbeterd door gebruik te maken van een daemon en mypyc. Dit is gedaan om ongemakken tijdens het annoteren te verhelpen en om de mogelijkheid te bieden met grote hoeveelheden code te werken.
Integratie met editors. We hebben middelen gecreƫerd ter ondersteuning van het uitvoeren van mypy in de editors die populair zijn binnen Dropbox. Dit omvat PyCharm, Vim en VS Code. Dit heeft het proces van het annoteren van code en het controleren van de functionaliteit aanzienlijk vereenvoudigd. Zulke acties zijn normaal tijdens het annoteren van bestaande code.
Statische analyse. We hebben een tool ontwikkeld voor het afleiden van functietekens met behulp van statische analysemiddelen. Deze tool kan alleen werken in relatief eenvoudige situaties, maar heeft ons geholpen om zonder veel moeite de type-dekking van de code te vergroten.
Ondersteuning voor externe bibliotheken. In veel van onze projecten maken we gebruik van de toolset SQLAlchemy. Dit maakt gebruik van de dynamische mogelijkheden van Python, die niet rechtstreeks door de typen van PEP 484 kunnen worden gemodelleerd. Volgens PEP 561 hebben we een bijbehorend stub-bestand gemaakt en een plugin voor mypy geschreven.), wat de ondersteuning van SQLAlchemy verbetert.
De uitdagingen waar we tegenaan liepen
De weg naar 4 miljoen regels getypeerde code was niet altijd gemakkelijk. We zijn onderweg verschillende hobbels tegengekomen en hebben een aantal fouten gemaakt. Hier zijn enkele van de problemen waarmee we te maken hebben gehad. We hopen dat het verhaal hierover anderen kan helpen soortgelijke problemen te voorkomen.
Gemiste bestanden. We begonnen met het controleren van slechts een beperkte hoeveelheid bestanden. Alles wat niet in die beperkte lijst viel, werd niet gecontroleerd. Bestanden werden aan de controlelijst toegevoegd wanneer ze voor het eerst annotaties kregen. Als iets werd geĆÆmporteerd uit een module die buiten het controlegebied lag, dan ging het om werken met types Any, die helemaal niet werden gecontroleerd. Dit leidde tot aanzienlijke verlies van type-precisie, vooral in de vroege fasen van de migratie. Deze aanpak werkte verrassend goed, hoewel het gebruikelijk was dat het toevoegen van bestanden aan het controlegebied problemen in andere delen van de codebasis onthulde. In het slechtste geval, wanneer twee geĆÆsoleerde codegebieden werden samengevoegd, waar de types onafhankelijk al waren gecontroleerd, bleek dat de types van deze gebieden niet met elkaar compatibel waren. Dit leidde tot de noodzaak om veel wijzigingen in de annotaties aan te brengen. Nu, terugkijkend, beseffen we dat we de basisbibliotheeksmodules al veel eerder aan het type controlegebied van mypy hadden moeten toevoegen. Dit zou ons werk veel voorspelbaarder hebben gemaakt.
Annotatie van oude code. Toen we begonnen te werken, hadden we ongeveer 4 miljoen bestaande regels Python-code. Het was duidelijk dat het annoteren van deze code een zware taak zou zijn. We hebben een tool ontwikkeld, genaamd PyAnnotate, die informatie over types kan verzamelen tijdens het uitvoeren van tests en die in staat is om type-annotaties aan de code toe te voegen op basis van de verzamelde informatie. Echter, we hebben niet veel brede adoptie van deze tool opgemerkt. Het verzamelen van type-informatie was traag en automatisch gegenereerde annotaties vereisten vaak vele handmatige aanpassingen. We hebben overwogen om deze tool automatisch te laten draaien bij elke codecheck, of om type-informatie te verzamelen op basis van de analyse van een kleine hoeveelheid echte webverzoeken, maar we hebben besloten dit niet te doen, omdat elk van deze benaderingen te riskant was.
Uiteindelijk kan worden opgemerkt dat het grootste deel van de code handmatig is geannoteerd door de eigenaren ervan. Om dit proces in de juiste richting te sturen, bereiden we rapporten voor over bijzonder belangrijke modules en functies die geannoteerd moeten worden. Het is bijvoorbeeld belangrijk om de bibliotheekmodule, die op honderden plaatsen wordt gebruikt, van type-annotaties te voorzien. Maar de oude service die door een nieuwe wordt vervangen, is al minder belangrijk om te annoteren. Daarnaast experimenteren we met het gebruik van statische analyse om type-annotaties voor oude code te genereren.
Cyclic imports. Earlier, I spoke about cyclic imports (the 'tangles of dependencies'), the existence of which complicated the acceleration of mypy. Additionally, we had to work hard to equip mypy with support for all types of idioms caused by these cyclic imports. Recently, we completed a major redesign project that fixed most of the issues mypy had regarding cyclic imports. These problems actually stemmed from the early days of the project, back in Alore, the teaching language that the mypy project was initially aimed at. The syntax of Alore easily solves the problems of cyclic import commands. Modern mypy inherited some limitations from its early straightforward implementation (which was great for Alore). Python complicates working with cyclic imports mainly due to the ambiguity of expressions. For example, during an assignment operation, a type alias may actually be determined. Mypy is not always able to detect such things until a large part of the import cycle has been processed. In Alore, such ambiguities did not exist. Poor decisions made in the early stages of system development can give programmers an unpleasant surprise many years later.
Summary: The Path to 5 Million Lines of Code and New Horizons
The mypy project has come a long way ā from early prototypes to a system that manages types for production code comprising 4 million lines. Over the development of mypy, standardization of type hints in Python has been achieved. Nowadays, a powerful ecosystem has developed around type checking for Python code. It includes library support, tools for IDEs and editors, and several type-checking systems, each with its own advantages and disadvantages.
Although type checking is already regarded as a given in Dropbox, I am confident that we are still in the early days of type checking for Python code. I believe that type checking technologies will continue to evolve and improve.
Als je nog niet met typecontroles in je grootschalige Python-project bent begonnen, weet dan dat dit een uitstekend moment is om over te schakelen naar statische typing. Ik heb gesproken met degenen die deze overstap hebben gemaakt. Niemand van hen heeft er spijt van gehad. Typecontroles maken van Python een taal die veel beter geschikt is voor het ontwikkelen van grote projecten dan 'gewone Python'.
Geachte lezers! Maak je gebruik van typecontroles in je Python-projecten?
Bron: habr.com
