[PYTHON] Extrayez les erreurs mypy que vous avez corrigées en conjonction avec git

19 Nouveaux diplômés. Depuis cette année, j'ai touché au côté serveur et fait diverses choses.

Cette fois, je vais parler de la façon d'afficher l'augmentation / la diminution de la sortie d'erreur mypy d'une manière facile à comprendre en conjonction avec git.

Préface: Qu'est-ce que mypy

C'est un outil qui effectue une analyse statique pour les annotations de type en python. Je vous recommande de lire l'article de l'ancêtre. mypy le fera J'ai fait mypy

introduction

Le début du problème était que la version de mypy dans mon cas n'avait pas été mise à jour depuis longtemps (0,540). Si vous regardez la Note de publication, elle indique vendredi 20 octobre 2017, etc.

Lorsque j'ai essayé d'installer la dernière version localement avec une sensation de légèreté, j'ai eu beaucoup d'erreurs liées aux éléments de contrôle ajoutés dans la mise à jour. Si vous ajoutez l'option de le supprimer pour le moment, cela passera, mais ... c'est ...

Réparons

Et j'ai essayé de corriger l'erreur en cours, mais cela devenait douloureux normalement. Étant donné que les erreurs sont inégalement réparties dans tout le code du projet, ce qui est assez important, il est mentalement pénible qu'aucune amélioration ne puisse être constatée en le corrigeant un peu ...

C'est impossible. Visualisons ...

Avait fait

La visualisation est une exagération (car ce sont des informations qui peuvent être vues depuis le début). Ne serait-il pas bien si la liste des erreurs que j'ai écrasées était affichée de manière facile à comprendre? J'ai pensé. La politique est simple: exécutez mypy deux fois avant et après le changement pour obtenir un diff. Il existe une politique selon laquelle il devrait être possible de faire quelque chose en appelant la différence entre l'arbre de travail et HEAD en conjonction avec git. Le temps d'exécution sera doublé, mais d'un autre côté, mypy ne peut être ciblé que sur le fichier de différence, donc je vais continuer avec l'espoir que tout va bien.

C'est pourquoi je l'ai fait. https://github.com/fujita-ma/mymypy

Il n'y a aucune raison sérieuse d'écrire dans la rouille, Comme il y avait beaucoup de traitement de texte ligne par ligne, je pense qu'il était facile d'écrire le traitement d'itérateur sans stress. C'est correct d'utiliser python, mais pour être honnête, je voulais le faire dans un langage que je n'utilisais pas au travail.

Essayez d'utiliser

Essayez-le avec le code de l'exemple mypy. http://www.mypy-lang.org/examples.html

main.py


class BankAccount:
    def __init__(self, initial_balance=0):
        self.balance = initial_balance
    def deposit(self, amount):
        self.balance += amount
    def withdraw(self, amount):
        self.balance -= amount
    def overdrawn(self):
        return self.balance < 0

my_account = BankAccount(15)
my_account.withdraw(5)
print(my_account.balance)

Lançons mypy.

❯ mypy --strict ./
main.py:2: error: Function is missing a type annotation
main.py:4: error: Function is missing a type annotation
main.py:6: error: Function is missing a type annotation
main.py:8: error: Function is missing a return type annotation
main.py:11: error: Call to untyped function "BankAccount" in typed context

J'obtiens une erreur. Après avoir validé cela une fois, modifiez certaines annotations et essayez d'exécuter respectivement mypy et mymypy.

main.py


class BankAccount:
    def __init__(self, initial_balance: int = 0) -> None:  # Annotated
        self.balance = initial_balance
    def deposit(self, amount):
        self.balance += amount
    def withdraw(self, amount):
        self.balance -= amount
    def overdrawn(self):
        return self.balance < 0

my_account = BankAccount(15)
my_account.withdraw(5)
print(my_account.balance)
❯ mypy --strict ./
main.py:4: error: Function is missing a type annotation
main.py:6: error: Function is missing a type annotation
main.py:8: error: Function is missing a return type annotation
main.py:12: error: Call to untyped function "withdraw" in typed context
❯ mymypy
main.py
-main.py:2:_: error: Function is missing a type annotation
main.py:4:4: error: Function is missing a type annotation
main.py:6:6: error: Function is missing a type annotation
main.py:8:8: error: Function is missing a return type annotation
-main.py:11:11: error: Call to untyped function "BankAccount" in typed context
+main.py:12:12: error: Call to untyped function "withdraw" in typed context

L'erreur écrasée est surlignée en rouge! De plus, en tant que sous-produit, l'erreur ajoutée est surlignée en vert. Il est courant que vous corrigiez une erreur et obteniez une autre erreur cachée. Je vais tout écraser correctement.

Si vous ajoutez correctement toutes les annotations, cela ressemblera à ↓.

main.py


class BankAccount:
    def __init__(self, initial_balance: int = 0) -> None:
        self.balance = initial_balance
    def deposit(self, amount: int) -> None:
        self.balance += amount
    def withdraw(self, amount: int) -> None:
        self.balance -= amount
    def overdrawn(self) -> bool:
        return self.balance < 0

my_account = BankAccount(15)
my_account.withdraw(5)
print(my_account.balance)
❯ mypy --strict ./

❯ mymypy
main.py
-main.py:2:_: error: Function is missing a type annotation
-main.py:4:_: error: Function is missing a type annotation
-main.py:6:_: error: Function is missing a type annotation
-main.py:8:_: error: Function is missing a return type annotation
-main.py:11:11: error: Call to untyped function "BankAccount" in typed context

J'ai pu écraser 5 erreurs par mon propre travail. Je suis heureux.

Essayez-le dans un référentiel approprié

Jouons un peu. Les révisions sont gérées selon git diff, donc si vous spécifiez un commit approprié, vous pouvez faire la différence entre elles. Jetez un œil au dépôt de mypy pour détecter les commits.

a5005f4aa977e4911bce5c828fd707ca8680d592 The `inner_types` attribute seems to have no effect. J'ai trouvé un commit qui semble avoir été refactorisé.

Clonons-le et exécutons-le sur mymypy.

❯ mymypy a5005f4~ a5005f4
mypy/checker.py
mypy/checker.py:64:64: error: Module 'mypy.semanal' has no attribute 'set_callable_name'
-mypy/checker.py:2813:_: error: Too many arguments for "PartialType"
-mypy/checker.py:2823:_: error: Too many arguments for "PartialType"
mypy/checker.py:2959:2959: error: unused 'type: ignore' comment
-mypy/checker.py:3022:_: error: "PartialType" has no attribute "inner_types"
-mypy/checker.py:3024:_: error: "PartialType" has no attribute "inner_types"
mypy/checker.py:4137:4133: error: unused 'type: ignore' comment
-mypy/checker.py:4311:_: error: "PartialType" has no attribute "inner_types"
mypy/checkexpr.py
mypy/checkexpr.py:203:203: error: unused 'type: ignore' comment
-mypy/checkexpr.py:592:_: error: "PartialType" has no attribute "inner_types"
-mypy/checkexpr.py:606:_: error: "PartialType" has no attribute "inner_types"
mypy/checkexpr.py:2368:2361: error: Returning Any from function declared to return "Optional[str]"
mypy/checkexpr.py:3003:2996: error: unused 'type: ignore' comment
mypy/type_visitor.py
mypy/type_visitor.py:167:167: error: unused 'type: ignore' comment
mypy/type_visitor.py:207:207: error: unused 'type: ignore' comment
mypy/type_visitor.py:229:229: error: unused 'type: ignore' comment
-mypy/type_visitor.py:293:_: error: "PartialType" has no attribute "inner_types"
mypy/types.py
mypy/types.py:190:190: error: unused 'type: ignore' comment
mypy/types.py:497:497: error: Returning Any from function declared to return "T"
mypy/types.py:520:520: error: Returning Any from function declared to return "T"
mypy/types.py:808:808: error: Returning Any from function declared to return "Union[Dict[str, Any], str]"
mypy/types.py:1557:1557: error: Returning Any from function declared to return "T"
mypy/types.py:1669:1669: error: Returning Any from function declared to return "T"
mypy/types.py:1789:1786: error: Returning Any from function declared to return "T"
mypy/types.py:1844:1841: error: unused 'type: ignore' comment
mypy/types.py:1889:1886: error: Returning Any from function declared to return "T"

Vous pouvez voir l'effet de la refactorisation. Amusant ✌ ('ω' ✌) Trois ✌ ('ω') ✌ Trois (✌'ω ') ✌ (Mot mort)

en conclusion

Je l'ai fait avec une politique appropriée après un changement d'humeur, mais je suis satisfait car il a pu s'afficher avec un bon feeling. Je vais l'utiliser pour mon entreprise car c'est une bonne affaire. ~~ Si vous l'utilisez réellement, vous trouverez de nombreux bugs ~~

Recommended Posts

Extrayez les erreurs mypy que vous avez corrigées en conjonction avec git
Notez que j'ai traité du HTML dans Beautiful Soup
Mémo de travail que j'ai essayé i18n avec l'application Flask
J'ai enregistré PyQCheck, une bibliothèque qui peut effectuer QuickCheck avec Python, dans PyPI.
J'ai essayé de prédire les chevaux qui seront dans le top 3 avec LightGBM