[PYTHON] En fait, j'ai tapé statiquement un extrait de code approprié avec mypy

référence:

J'ai essayé la vérification de type statique en ajoutant une annotation de type de mypy au code de la commande que j'ai écrite plus tôt en Python.

De nombreux stubs de bibliothèque standard sont déjà définis dans mypy, mais je n'avais pas assez de classes et de méthodes pour les modules argparse, operator et itertools utilisés dans la commande which, j'ai donc essayé de définir les stubs moi-même. C'était un peu difficile car je n'étais pas habitué à la définition de ce talon.

stubs/argparse.py


from typing import Any, List, Sequence, Undefined

class Namespace:
    def __init__(self) -> None:
        self.commands = Undefined(List[str])
        self.is_all = Undefined(bool)
        self.is_silent = Undefined(bool)

class ArgumentParser:
    def set_defaults(self, **kwargs: Any) -> None: pass
    def add_argument(self, *args: Sequence[str], **kwargs: Any) -> None: pass
    def parse_args(self, args: Sequence[str], namespace: Namespace = None) -> Namespace: pass

stubs/itertools.py


from typing import Iterable, typevar

_T = typevar('_T')

class chain:
    @classmethod
    def from_iterable(cls, iterable: Iterable[Iterable[_T]]) -> Iterable[_T]: pass

stubs/operator.py


from typing import Any, Function, Sequence, typevar

_T = typevar('_T')

def itemgetter(item: _T, *items: Sequence[_T]) -> Function[[Any], _T]: pass

Définissez des variables d'environnement pour rendre vos stubs définis visibles par mypy.

python


(mypy)$ export MYPYPATH=./stubs/

En fait, j'étais un peu confus car cela ne fonctionnait pas parce que j'ai écrit l'annotation de type tout en répétant la définition du stub et la vérification de type. Je pense que c'est une question de familiarité.

Enfin, j'ai ajouté l'annotation de type à la source de quelle commande which_with_statally_typed.py?

Le diff avec le code original ressemble à ceci.

python


$ diff -u which.py which_with_statically_typed.py 
--- which.py	2014-12-26 12:22:31.000000000 +0900
+++ which_with_statically_typed.py	2014-12-26 16:06:28.000000000 +0900
@@ -7,8 +7,10 @@
 from os.path import join as pathjoin
 from operator import itemgetter
 
+from typing import List, Sequence, Tuple  # pragma: no flakes
 
-def search(cmd, paths, is_all=False):
+
+def search(cmd: str, paths: List[str], is_all: bool=False):
     for path in paths:
         for match in glob.glob(pathjoin(path, cmd)):
             if os.access(match, os.X_OK):
@@ -17,7 +19,7 @@
                     raise StopIteration
 
 
-def parse_argument(args=None):
+def parse_argument(args: Sequence[str]=None) -> argparse.Namespace:
     parser = argparse.ArgumentParser()
     parser.set_defaults(is_all=False, is_silent=False, commands=[])
     parser.add_argument(
@@ -29,23 +31,23 @@
         help="No output, just return 0 if any of the executables are found, "
              "or 1 if none are found.")
     parser.add_argument("commands", nargs="*")
-    args = parser.parse_args(args or sys.argv[1:])
-    return args
+    namespace = parser.parse_args(args or sys.argv[1:])
+    return namespace
 
 
-def main(cmd_args=None):
+def main(cmd_args: Sequence[str]=None) -> int:
     args = parse_argument(cmd_args)
     if not args.commands:
         print('Usage: python which.py cmd1 [cmd2 ...]')
         return 0
 
     env_paths = os.environ['PATH'].split(':')
-    result = []
+    result = []  # type: List[Tuple[int, List[str]]]
     for cmd in args.commands:
         founds = list(search(cmd, env_paths, args.is_all))
         result.append((0, founds) if founds else (1, [cmd]))
 
-    status_code = max(map(itemgetter(0), result))
+    status_code = max(map(itemgetter(0), result))  # type: int
     if not args.is_silent:
         cmd_paths = [paths for ret_val, paths in result if ret_val == 0]
         for cmd_path in chain.from_iterable(cmd_paths):

La source entière se trouve sur misc / which.

Recommended Posts

En fait, j'ai tapé statiquement un extrait de code approprié avec mypy
J'ai fait une loterie avec Python.
J'ai créé un démon avec Python
J'ai essayé de mettre en œuvre une blockchain qui fonctionne réellement avec environ 170 lignes
J'ai fait un compteur de caractères avec Python
J'ai dessiné une carte thermique avec Seaborn [Python]
J'ai essayé un langage fonctionnel avec Python
Ce que j'ai fait avec les tableaux Python
J'ai fait une carte hexadécimale avec Python
J'ai fait un jeu de vie avec Numpy
Un monde typé qui commence par Python
J'ai fait un générateur Hanko avec GAN
J'ai fait un jeu rogue-like avec Python
J'ai fait un simple blackjack avec Python
J'ai créé un fichier de configuration avec Python
J'ai fait une application WEB avec Django
J'ai fait un simulateur de neurones avec Python
J'ai fait un robot de remplacement de tampon avec une ligne
J'ai fait une prévision météo de type bot avec Python.
J'ai créé une application graphique avec Python + PyQt5
J'ai essayé de créer un bloqueur de filles pourries sur Twitter avec Python ①
Je veux faire un jeu avec Python
J'ai fait un truc fou appelé tuple typé
[Python] J'ai créé un téléchargeur Youtube avec Tkinter.
J'obtiens une UnicodeDecodeError lors de l'exécution avec mod_wsgi
J'ai fait un simple portefeuille de Bitcoin avec pycoin
J'ai créé un Bot LINE avec Serverless Framework!
J'ai joué avec Diamond, un outil de collecte de métriques
J'ai fait un graphique de nombres aléatoires avec Numpy
Je veux écrire dans un fichier avec Python
J'ai essayé d'utiliser la base de données (sqlite3) avec kivy
J'ai fait un jeu de cueillette avec Python
Made Mattermost Bot avec Python (+ Flask)