diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bf1eaa689eb7..616538dab9e6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,6 +14,8 @@ are important to the project's success. * [Contact us](#discussion) before starting significant work. * IMPORTANT: For new libraries, [get permission from the library owner first](#adding-a-new-library). * Create your stubs [conforming to the coding style](#stub-file-coding-style). + * Add tests for your stubs to `test_data`. These tests are not meant + to be executable. Type checkers analyze them statically. * Make sure `runtests.sh` passes cleanly on Mypy, pytype, and flake8. 4. [Submit your changes](#submitting-changes): * Open a pull request diff --git a/stdlib/2/__builtin__.pyi b/stdlib/2/__builtin__.pyi index 82b8e7890df5..0c2357bccfa9 100644 --- a/stdlib/2/__builtin__.pyi +++ b/stdlib/2/__builtin__.pyi @@ -43,6 +43,7 @@ class object: def __format__(self, format_spec: str) -> str: ... def __getattribute__(self, name: str) -> Any: ... def __delattr__(self, name: str) -> None: ... + def __sizeof__(self) -> int: ... class type: __bases__ = ... # type: Tuple[type, ...] diff --git a/stdlib/2/typing.pyi b/stdlib/2/typing.pyi index e591333f3d34..b7da4d0d6bdd 100644 --- a/stdlib/2/typing.pyi +++ b/stdlib/2/typing.pyi @@ -355,8 +355,17 @@ def cast(tp: Type[_T], obj: Any) -> _T: ... # Type constructors -# NamedTuple is special-cased in the type checker; the initializer is ignored. -def NamedTuple(typename: str, fields: Iterable[Tuple[str, Any]], *, - verbose: bool = ..., rename: bool = ...) -> Type[tuple]: ... +# NamedTuple is special-cased in the type checker +class NamedTuple(tuple): + _fields = ... # type: Tuple[str, ...] + + def __init__(self, typename: str, fields: Iterable[Tuple[str, Any]], *, + verbose: bool = ..., rename: bool = ...) -> None: ... + + @classmethod + def _make(cls, iterable: Iterable[Any]) -> NamedTuple: ... + + def _asdict(self) -> dict: ... + def _replace(self, **kwargs: Any) -> NamedTuple: ... def NewType(name: str, tp: Type[_T]) -> Type[_T]: ... diff --git a/stdlib/3/builtins.pyi b/stdlib/3/builtins.pyi index 8068890bdfaa..7a215bdc50cf 100644 --- a/stdlib/3/builtins.pyi +++ b/stdlib/3/builtins.pyi @@ -46,6 +46,7 @@ class object: def __format__(self, format_spec: str) -> str: ... def __getattribute__(self, name: str) -> Any: ... def __delattr__(self, name: str) -> None: ... + def __sizeof__(self) -> int: ... if sys.version_info >= (3, 6): def __init_subclass__(cls) -> None: ... diff --git a/stdlib/3/typing.pyi b/stdlib/3/typing.pyi index c48f4a8b18c9..01fd87f841e8 100644 --- a/stdlib/3/typing.pyi +++ b/stdlib/3/typing.pyi @@ -462,8 +462,17 @@ def cast(tp: Type[_T], obj: Any) -> _T: ... # Type constructors -# NamedTuple is special-cased in the type checker; the initializer is ignored. -def NamedTuple(typename: str, fields: Iterable[Tuple[str, Any]], *, - verbose: bool = ..., rename: bool = ..., module: str = None) -> Type[tuple]: ... +# NamedTuple is special-cased in the type checker +class NamedTuple(tuple): + _fields = ... # type: Tuple[str, ...] + + def __init__(self, typename: str, fields: Iterable[Tuple[str, Any]], *, + verbose: bool = ..., rename: bool = ..., module: Any = ...) -> None: ... + + @classmethod + def _make(cls, iterable: Iterable[Any]) -> NamedTuple: ... + + def _asdict(self) -> dict: ... + def _replace(self, **kwargs: Any) -> NamedTuple: ... def NewType(name: str, tp: Type[_T]) -> Type[_T]: ... diff --git a/test_data/stdlib/2and3/builtins_test.py b/test_data/stdlib/2and3/builtins_test.py new file mode 100644 index 000000000000..118f30f085a7 --- /dev/null +++ b/test_data/stdlib/2and3/builtins_test.py @@ -0,0 +1,8 @@ +def test_object_sizeof(): + # type: () -> None + + class C(object): + pass + + object().__sizeof__() + C().__sizeof__() diff --git a/test_data/stdlib/2and3/collections_test.py b/test_data/stdlib/2and3/collections_test.py new file mode 100644 index 000000000000..114bac7ad1df --- /dev/null +++ b/test_data/stdlib/2and3/collections_test.py @@ -0,0 +1,14 @@ +from collections import namedtuple + + +def test_collections_namedtuple(): + # type: () -> None + Point = namedtuple('Point', 'x y') + p = Point(1, 2) + + p._replace(y=3.14) + p._asdict() + p.x, p.y + p[0] + p[1] + p.index(1) + Point._make([('x', 1), ('y', 3.14)]) diff --git a/test_data/stdlib/2and3/typing_test.py b/test_data/stdlib/2and3/typing_test.py new file mode 100644 index 000000000000..e2015ff431ab --- /dev/null +++ b/test_data/stdlib/2and3/typing_test.py @@ -0,0 +1,14 @@ +from typing import NamedTuple + + +def test_typing_namedtuple(): + # type: () -> None + Point = NamedTuple('Point', [('x', float), ('y', float)]) + p = Point(1, 2) + + p._replace(y=3.14) + p._asdict() + p.x, p.y + p[0] + p[1] + p.index(1) + Point._make([('x', 1), ('y', 3.14)]) diff --git a/test_data/stdlib/3.6/typing_test.py b/test_data/stdlib/3.6/typing_test.py new file mode 100644 index 000000000000..6ee0c0794cb1 --- /dev/null +++ b/test_data/stdlib/3.6/typing_test.py @@ -0,0 +1,16 @@ +from typing import NamedTuple + + +class Point(NamedTuple): + x: float + y: float + + +def test_typing_namedtuple(): + # type: () -> None + p = Point(1, 2) + p._asdict() + p.x, p.y + p[0] + p[1] + p.index(1) + Point._make([('x', 1), ('y', 3.14)]) diff --git a/tests/mypy_test.py b/tests/mypy_test.py index d474009e4d01..6a4e53510e60 100755 --- a/tests/mypy_test.py +++ b/tests/mypy_test.py @@ -63,7 +63,7 @@ def libpath(major, minor): versions.append('2and3') paths = [] for v in versions: - for top in ['stdlib', 'third_party']: + for top in ['stdlib', 'third_party', 'test_data/stdlib', 'test_data/third_party']: p = os.path.join(top, v) if os.path.isdir(p): paths.append(p) diff --git a/tests/pytype_test.py b/tests/pytype_test.py index e7475c0be115..ec292bf2cd86 100755 --- a/tests/pytype_test.py +++ b/tests/pytype_test.py @@ -70,7 +70,7 @@ def pytype_test(args): print("Cannot run pytd. Did you install pytype?") return 0, 0 - wanted = re.compile(r"stdlib/(2|2\.7|2and3)/.*\.pyi$") + wanted = re.compile(r"stdlib/(2|2\.7|2and3)/.*\.pyi?$") skipped = re.compile("(%s)$" % "|".join(load_blacklist())) files = [] @@ -80,6 +80,15 @@ def pytype_test(args): if wanted.search(f) and not skipped.search(f): files.append(f) + # XXX: Temporarily disabled checking test_data/ due to a bug + # in pytype related to handling type hints in function comments + + # for root, _, filenames in os.walk("test_data/stdlib"): + # for f in sorted(filenames): + # f = os.path.join(root, f) + # if wanted.search(f) and not skipped.search(f): + # files.append(f) + running_tests = collections.deque() max_code, runs, errors = 0, 0, 0 print("Running pytype tests...")