Skip to content

Commit ab7dbed

Browse files
committed
Drop Pytype support
Resolves #30
1 parent 39e58ff commit ab7dbed

File tree

8 files changed

+64
-494
lines changed

8 files changed

+64
-494
lines changed

.github/copilot-instructions.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,17 @@ The validation logic uses a recursive pattern:
4747

4848
Code contains extensive typechecker annotations:
4949
- `# type: ignore[error-code]` for mypy
50-
- `# pytype` for pytype
5150
- `# pyre` for pyre
5251
- `# pyright` for pyright
5352

54-
When adding features, test against all typecheckers: `make typecheck` runs mypy, pyright, pyre, and pytype.
53+
When adding features, test against all typecheckers: `make typecheck` runs mypy, pyright, and pyre.
5554

5655
## Development Workflows
5756

5857
### Testing Commands (Makefile)
5958
- `make test` - Run unittest against current Python version
6059
- `make testall` - Run tox across Python 3.9-3.13 (uses venv3.9/, venv3.10/, etc.)
61-
- `make typecheck` - Run all typecheckers (mypy, pyright, pyre, pytype)
60+
- `make typecheck` - Run all typecheckers (mypy, pyright, pyre)
6261
- `make format` - Format with black + isort
6362
- `make lint` - Check black/isort/flake8 compliance
6463

Makefile

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ path := .
1313

1414
# ex: "10.14.6" (if on macOS) or "" if not on macOS
1515
macos_version := $(shell which sw_vers > /dev/null 2>&1 && sw_vers -productVersion)
16-
pytype_path := $(shell which pytype)
1716

1817
.PHONY: help
1918
help: ## Show this help message.
@@ -65,7 +64,7 @@ flake: ## Run flake8 linter.
6564

6665

6766
.PHONY: typecheck
68-
typecheck: mypy pyright pyre pytype ## Run all typecheckers.
67+
typecheck: mypy pyright pyre ## Run all typecheckers.
6968

7069

7170
.PHONY: mypy
@@ -89,15 +88,6 @@ pyre:
8988
endif
9089

9190

92-
.PHONY: pytype
93-
ifneq "$(pytype_path)" ""
94-
pytype: ## Run pytype typechecker.
95-
pytype --keep-going trycast/__init__.py tests.py
96-
else
97-
pytype:
98-
endif
99-
100-
10191
.PHONY: coverage
10292
coverage: ## Generate code coverage report.
10393
coverage run -m unittest

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,6 @@ Trycast does type check successfully with the following type checkers:
340340
* [Mypy]
341341
* [Pyright] / [Pylance]
342342
* [Pyre]
343-
* [Pytype]
344343
345344
346345
## API Reference
@@ -526,6 +525,8 @@ raised exceptions, and other details.
526525
527526
* Drop support for Python 3.8.
528527
* Remove supporting code for Python 3.8's neutered TypedDict.
528+
* Drop support for Pytype type checker, since it has been
529+
[deprecated](https://github.com/google/pytype/blob/main/README.md).
529530
530531
### v1.2.1
531532
@@ -605,7 +606,7 @@ raised exceptions, and other details.
605606
* trycast has been in production use for over a year
606607
at [at least one company] without issues.
607608
* trycast supports all major Python type checkers
608-
(Mypy, Pyright/Pylance, Pyre, Pytype).
609+
(Mypy, Pyright/Pylance, Pyre).
609610
* trycast's initial API is finalized.
610611
* Fix `coverage` to be a dev-dependency rather than a regular dependency.
611612

benchmarks/data/http_request_parsing_example.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
from typing import Literal, Mapping, Optional
2-
from typing import (
3-
TypedDict as RichTypedDict, # type: ignore[not-supported-yet] # pytype
4-
)
2+
from typing import TypedDict as RichTypedDict
53

64

75
# For test_http_request_parsing_example

poetry.lock

Lines changed: 1 addition & 388 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ mypy = "*"
3636
mypy_extensions = "*"
3737
pyright = "*"
3838
pyre-check = "*"
39-
# NOTE: Duplicated in: [tool.tox] > legacy_tox_ini > [testenv] > deps
40-
pytype = { version = "==2024.04.11", python = ">=3.7.4,<3.10" }
4139
tox = ">=4.0.0,<5.0.0"
4240
black = "==24.3.0"
4341
isort = "^5.9.1"
@@ -73,7 +71,6 @@ profile = "black"
7371
atomic = true
7472
line_length = 88
7573
skip_glob = [
76-
".pytype",
7774
"test_data/forwardrefs_example*.py",
7875
"test_data/type_statement_example.py",
7976
"venv*",
@@ -94,7 +91,6 @@ isolated_build = True
9491
[testenv]
9592
deps =
9693
mypy
97-
pytype == 2024.04.11 ; python_version < "3.10"
9894
typing-extensions >= 4.11.0rc1
9995
commands =
10096
python3 -m unittest

tests.py

Lines changed: 26 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,8 @@
2929
Tuple,
3030
Type,
3131
)
32-
from typing import (
33-
TypedDict as NativeTypedDict, # type: ignore[not-supported-yet] # pytype
34-
)
35-
from typing import (
36-
TypedDict as RichTypedDict, # type: ignore[not-supported-yet] # pytype
37-
)
32+
from typing import TypedDict as NativeTypedDict
33+
from typing import TypedDict as RichTypedDict
3834
from typing import TypeVar, Union, cast
3935
from unittest import SkipTest, TestCase
4036

@@ -74,9 +70,9 @@ def eval_type(x, y, z):
7470

7571
# ParamSpec
7672
if sys.version_info >= (3, 13):
77-
from typing import ParamSpec # type: ignore[import-error] # pytype
73+
from typing import ParamSpec
7874
else:
79-
from typing_extensions import ParamSpec # type: ignore[not-supported-yet] # pytype
75+
from typing_extensions import ParamSpec
8076

8177
_FAILURE = object()
8278

@@ -1156,12 +1152,12 @@ def test_typeddict_required_notrequired(self) -> None:
11561152
self.assertIs(typing.Required, typing_extensions.Required) # type: ignore[16] # pyre
11571153
self.assertIs(typing.NotRequired, typing_extensions.NotRequired) # type: ignore[16] # pyre
11581154

1159-
class TotalMovie(typing_extensions.TypedDict): # type: ignore[not-supported-yet] # pytype
1155+
class TotalMovie(typing_extensions.TypedDict):
11601156
title: str
1161-
year: typing_extensions.NotRequired[int] # type: ignore[not-supported-yet] # pytype
1157+
year: typing_extensions.NotRequired[int]
11621158

11631159
class NontotalMovie(typing_extensions.TypedDict, total=False):
1164-
title: typing_extensions.Required[str] # type: ignore[not-supported-yet] # pytype
1160+
title: typing_extensions.Required[str]
11651161
year: int
11661162

11671163
# TotalMovie
@@ -1186,7 +1182,7 @@ def test_typeddict_readonly(self) -> None:
11861182
if sys.version_info >= (3, 13):
11871183
self.assertIs(typing.ReadOnly, typing_extensions.ReadOnly) # type: ignore[attr-defined, 16] # mypy, pyre
11881184

1189-
class Movie(typing_extensions.TypedDict): # type: ignore[not-supported-yet] # pytype
1185+
class Movie(typing_extensions.TypedDict):
11901186
title: str
11911187
year: int
11921188

@@ -1519,22 +1515,22 @@ def test_any(self) -> None:
15191515
if sys.version_info >= (3, 11):
15201516

15211517
def test_never(self) -> None:
1522-
self.assertTryCastFailure(Never, "words") # type: ignore[wrong-arg-types] # pytype
1523-
self.assertTryCastFailure(Never, 1) # type: ignore[wrong-arg-types] # pytype
1524-
self.assertTryCastFailure(Never, None) # type: ignore[wrong-arg-types] # pytype
1525-
self.assertTryCastFailure(Never, str) # type: ignore[wrong-arg-types] # pytype
1518+
self.assertTryCastFailure(Never, "words")
1519+
self.assertTryCastFailure(Never, 1)
1520+
self.assertTryCastFailure(Never, None)
1521+
self.assertTryCastFailure(Never, str)
15261522

1527-
self.assertTryCastFailure(Never, ValueError) # type: ignore[wrong-arg-types] # pytype
1528-
self.assertTryCastFailure(Never, ValueError()) # type: ignore[wrong-arg-types] # pytype
1523+
self.assertTryCastFailure(Never, ValueError)
1524+
self.assertTryCastFailure(Never, ValueError())
15291525

15301526
def test_noreturn(self) -> None:
1531-
self.assertTryCastFailure(NoReturn, "words") # type: ignore[wrong-arg-types] # pytype
1532-
self.assertTryCastFailure(NoReturn, 1) # type: ignore[wrong-arg-types] # pytype
1533-
self.assertTryCastFailure(NoReturn, None) # type: ignore[wrong-arg-types] # pytype
1534-
self.assertTryCastFailure(NoReturn, str) # type: ignore[wrong-arg-types] # pytype
1527+
self.assertTryCastFailure(NoReturn, "words")
1528+
self.assertTryCastFailure(NoReturn, 1)
1529+
self.assertTryCastFailure(NoReturn, None)
1530+
self.assertTryCastFailure(NoReturn, str)
15351531

1536-
self.assertTryCastFailure(NoReturn, ValueError) # type: ignore[wrong-arg-types] # pytype
1537-
self.assertTryCastFailure(NoReturn, ValueError()) # type: ignore[wrong-arg-types] # pytype
1532+
self.assertTryCastFailure(NoReturn, ValueError)
1533+
self.assertTryCastFailure(NoReturn, ValueError())
15381534

15391535
# === Forward References ===
15401536

@@ -1885,7 +1881,7 @@ class Point3D(Point2D, total=False): # type: ignore[reportGeneralTypeIssues] #
18851881
if sys.version_info < (3, 9):
18861882

18871883
def test_rejects_python_3_8_typeddict_when_strict_is_true(self) -> None:
1888-
class Point2D(typing.TypedDict): # type: ignore[not-supported-yet] # pytype
1884+
class Point2D(typing.TypedDict):
18891885
x: int
18901886
y: int
18911887

@@ -2884,16 +2880,14 @@ def _demands_a_str(value: str) -> str:
28842880
# self._demands_a_never(value) # ensure typechecks
28852881
#
28862882
# @staticmethod
2887-
# def _demands_a_never(value: NoReturn) -> NoReturn: # type: ignore[invalid-annotation] # pytype
2883+
# def _demands_a_never(value: NoReturn) -> NoReturn:
28882884
# raise ValueError("expected this code to be unreachable")
28892885

28902886

28912887
# ------------------------------------------------------------------------------
28922888
# Internal: TestIsTypedDict
28932889

2894-
from typing import (
2895-
TypedDict as TypingTypedDict, # type: ignore[not-supported-yet] # pytype
2896-
)
2890+
from typing import TypedDict as TypingTypedDict
28972891

28982892
from trycast import _is_typed_dict
28992893

@@ -2903,9 +2897,7 @@ class TypingPoint(TypingTypedDict):
29032897
y: int
29042898

29052899

2906-
from typing_extensions import (
2907-
TypedDict as TypingExtensionsTypedDict, # type: ignore[not-supported-yet] # pytype
2908-
)
2900+
from typing_extensions import TypedDict as TypingExtensionsTypedDict
29092901

29102902

29112903
class TypingExtensionsPoint(TypingExtensionsTypedDict):
@@ -2950,8 +2942,8 @@ def _tag(tag_name: str) -> Callable[[Callable[_P, _R]], Callable[_P, _R]]: # ty
29502942
$ TRYCAST_SKIP_TEST_TAGS=pyright,pyre python -m unittest
29512943
"""
29522944

2953-
def decorate(f: Callable[_P, _R]) -> Callable[_P, _R]: # type: ignore[invalid-annotation] # pytype
2954-
def decorated(*args: _P.args, **kwargs: _P.kwargs) -> _R: # type: ignore[invalid-annotation] # pytype
2945+
def decorate(f: Callable[_P, _R]) -> Callable[_P, _R]:
2946+
def decorated(*args: _P.args, **kwargs: _P.kwargs) -> _R:
29552947
if tag_name in os.environ.get("TRYCAST_SKIP_TEST_TAGS", "").split(","):
29562948
raise SkipTest(f"skipping test tagged {tag_name}")
29572949
return f(*args, **kwargs)
@@ -3012,23 +3004,5 @@ def test_no_pyre_typechecker_errors_exist(self) -> None:
30123004

30133005
self.fail(f"pyre typechecking failed:\n\n{output_str}")
30143006

3015-
@_tag("pytype")
3016-
def test_no_pytype_typechecker_errors_exist(self) -> None:
3017-
try:
3018-
subprocess.check_output(
3019-
["pytype", "--keep-going", "trycast/__init__.py", "tests.py"],
3020-
env={"LANG": "en_US.UTF-8", "PATH": os.environ.get("PATH", "")},
3021-
stderr=subprocess.STDOUT,
3022-
)
3023-
except subprocess.CalledProcessError as e: # pragma: no cover
3024-
self.fail(
3025-
f'pytype typechecking failed:\n\n{e.output.decode("utf-8").strip()}'
3026-
)
3027-
except FileNotFoundError:
3028-
if sys.version_info >= (3, 10):
3029-
self.skipTest("Cannot run pytype on Python 3.10+")
3030-
else: # pragma: no cover
3031-
raise
3032-
30333007

30343008
# ------------------------------------------------------------------------------

0 commit comments

Comments
 (0)