Referenz:
Ich habe versucht, statische Typen zu überprüfen, indem ich dem Code des Befehls, den ich zuvor in Python geschrieben habe, eine Typanmerkung von mypy hinzugefügt habe.
Viele Standard-Bibliotheksstubs sind bereits in mypy definiert, aber ich hatte nicht genügend Klassen und Methoden für die Module argparse, operator und itertools, die in diesem Befehl verwendet wurden. Deshalb habe ich versucht, die Stubs selbst zu definieren. Es war ein wenig schwierig, weil ich nicht an die Definition dieses Stubs gewöhnt war.
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
Legen Sie Umgebungsvariablen fest, um Ihre definierten Stubs für mypy sichtbar zu machen.
python
(mypy)$ export MYPYPATH=./stubs/
Eigentlich war ich ein wenig verwirrt, weil es nicht funktioniert hat, weil ich die Typanmerkung geschrieben habe, während ich die Definition des Stubs und die Typprüfung wiederholt habe. Ich denke, es ist eine Frage der Vertrautheit.
Schließlich habe ich die Typanmerkung zu der Quelle des Befehls [which_with_static_typed.py] hinzugefügt (https://bitbucket.org/t2y/misc/src/0d4cdb82627db0c5abeaead22f56d02b6dc8ed7e/which/which_with_static_defed).
Das Diff mit dem Originalcode sieht so aus.
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):
Die gesamte Quelle befindet sich unter misc / which.
Recommended Posts