Skip to content

Commit 2c7f10e

Browse files
authored
Support PEP 561 typing (#6)
* Support PEP 561 typing * Fix lint --------- Co-authored-by: Jay Qi <jayqi@users.noreply.github.com>
1 parent 57e2573 commit 2c7f10e

File tree

6 files changed

+95
-80
lines changed

6 files changed

+95
-80
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## v1.2.0 (2024-03-19)
4+
5+
- Fixed the type signatures of `typenames` and `parse_type_tree` to reflect the typing of input type annotations, according to static type checkers.
6+
- Added [PEP 561 `py.typed` marker file](https://peps.python.org/pep-0561/#packaging-type-information) to indicate that the package supports type checking.
7+
38
## v1.1.0 (2024-03-08)
49

510
- Changed `REMOVE_ALL_MODULES`'s regex pattern to also remove `<locals>` from rendered output. `<locals>` typically appears in a type's qualified name if the type was defined within the local scope of a function or class method. ([PR #4](https://github.com/jayqi/typenames/pull/4))

pyproject.toml

Lines changed: 14 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -35,26 +35,22 @@ tests = ["pytest>=6"]
3535
"Changelog" = "https://jayqi.github.io/typenames/stable/changelog/"
3636

3737
[tool.hatch.version]
38-
path = "typenames.py"
39-
40-
[tool.hatch.build]
41-
exclude = ["inspect_types/", "docs/", "mkdocs.yml"]
42-
38+
path = "typenames/__init__.py"
4339

4440
## DEFAULT ENVIRONMENT ##
4541

4642
[tool.hatch.envs.default]
47-
dependencies = ["black", "ipython", "mypy", "reprexlite", "ruff"]
43+
dependencies = ["ipython", "mypy", "reprexlite", "ruff"]
4844
python = "3.10"
4945
path = ".venv"
5046

5147
[tool.hatch.envs.default.scripts]
48+
format = ["ruff format"]
5249
lint = [
53-
"black --check typenames.py tests.py",
54-
"ruff check typenames.py tests.py",
50+
"ruff format --check",
51+
"ruff check",
5552
]
56-
typecheck = ["mypy typenames.py --install-types --non-interactive"]
57-
53+
typecheck = ["mypy --install-types --non-interactive"]
5854

5955
## TESTS ENVIRONMENT ##
6056

@@ -67,10 +63,9 @@ template = "tests"
6763
python = ["3.8", "3.9", "3.10", "3.11", "3.12"]
6864

6965
[tool.hatch.envs.tests.scripts]
70-
run = "pytest tests.py --cov=typenames --cov-report=term --cov-report=html --cov-report=xml"
66+
run = "pytest tests --cov=typenames --cov-report=term --cov-report=html --cov-report=xml"
7167
run-debug = "run --pdb"
7268

73-
7469
## DOCS ENVIRONMENT ##
7570

7671
[tool.hatch.envs.docs]
@@ -91,7 +86,6 @@ build = [
9186
"mkdocs build",
9287
]
9388

94-
9589
## INSPECT-TYPES ENVIRONMENT ##
9690

9791
[tool.hatch.envs.inspect-types]
@@ -109,45 +103,30 @@ jupyter nbconvert inspect_types/_inspect_types.ipynb \
109103
--execute \
110104
--allow-errors"""
111105

112-
113106
## TOOLS ##
114107

115-
[tool.black]
116-
line-length = 99
117-
include = '\.pyi?$'
118-
exclude = '''
119-
/(
120-
\.eggs
121-
| \.git
122-
| \.mypy_cache
123-
| \.tox
124-
| \.venv
125-
| build
126-
| dist
127-
| tests/assets
128-
)/
129-
'''
130-
131108
[tool.ruff]
132109
line-length = 99
110+
src = ["typenames", "tests"]
111+
112+
[tool.ruff.lint]
133113
select = [
134114
"E", # Pyflakes
135115
"F", # Pycodestyle
136116
"I", # isort
137117
]
138-
src = ["typenames.py", "tests.py"]
139118
unfixable = ["F"]
140119

141-
[tool.ruff.isort]
120+
[tool.ruff.lint.isort]
142121
known-first-party = ["typenames"]
143122
force-sort-within-sections = true
144123

145124
[tool.mypy]
146-
ignore_missing_imports = true
125+
files = ["typenames", "tests/typechecks.py"]
147126

148127
[tool.pytest.ini_options]
149128
minversion = "6.0"
150-
testpaths = ["tests.py"]
129+
testpaths = ["tests"]
151130

152131
[tool.coverage.run]
153-
source = ["typenames.py"]
132+
source = ["typenames"]

tests.py renamed to tests/test_typenames.py

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,19 @@ class MyTypedDict(typing.TypedDict):
5050
(typing.List[int], "List[int]"),
5151
(typing.Tuple[str, int], "Tuple[str, int]"),
5252
(typing.Optional[int], "Optional[int]"),
53-
(MyClass, "tests.MyClass"),
54-
(OuterClass.InnerClass, "tests.OuterClass.InnerClass"),
55-
(typing.List[MyClass], "List[tests.MyClass]"),
56-
(typing.Optional[typing.List[MyClass]], "Optional[List[tests.MyClass]]"),
53+
(MyClass, "test_typenames.MyClass"),
54+
(OuterClass.InnerClass, "test_typenames.OuterClass.InnerClass"),
55+
(typing.List[MyClass], "List[test_typenames.MyClass]"),
56+
(typing.Optional[typing.List[MyClass]], "Optional[List[test_typenames.MyClass]]"),
5757
(typing.Union[float, int], "Union[float, int]"),
5858
(typing.Dict[str, int], "Dict[str, int]"),
5959
(typing.Any, "Any"),
6060
(typing.Dict[str, typing.Any], "Dict[str, Any]"),
6161
(typing.Callable[..., str], "Callable[..., str]"),
6262
(typing.Callable[[int], str], "Callable[[int], str]"),
6363
(typing.Callable[[int, float], str], "Callable[[int, float], str]"),
64-
(MyGeneric[int], "tests.MyGeneric[int]"),
65-
(MyEnum, "tests.MyEnum"),
64+
(MyGeneric[int], "test_typenames.MyGeneric[int]"),
65+
(MyEnum, "test_typenames.MyEnum"),
6666
(typing.List["int"], "List[int]"),
6767
(typing.List["typing.Any"], "List[Any]"),
6868
(typing.List["enum.Enum"], "List[enum.Enum]"),
@@ -71,7 +71,7 @@ class MyTypedDict(typing.TypedDict):
7171
# Python 3.8 adds typing.Literal, typing.Final, typing.TypedDict
7272
(typing.Literal["s", 0, MyEnum.MEMBER1], "Literal['s', 0, MyEnum.MEMBER1]"),
7373
(typing.Final[int], "Final[int]"),
74-
(MyTypedDict, "tests.MyTypedDict"),
74+
(MyTypedDict, "test_typenames.MyTypedDict"),
7575
]
7676

7777

@@ -130,19 +130,19 @@ class FnScopeClass: ...
130130

131131
# Default removal
132132
assert typenames(typing.Any) == "Any"
133-
assert typenames(MyClass) == "tests.MyClass"
133+
assert typenames(MyClass) == "test_typenames.MyClass"
134134
assert typenames(OtherModuleClass) == "other_module.OtherModuleClass"
135-
assert typenames(FnScopeClass) == "tests.test_remove_modules.<locals>.FnScopeClass"
135+
assert typenames(FnScopeClass) == "test_typenames.test_remove_modules.<locals>.FnScopeClass"
136136

137137
# Override
138-
config = TypenamesConfig(remove_modules=["tests"])
138+
config = TypenamesConfig(remove_modules=["test_typenames"])
139139
assert typenames(typing.Any, config=config) == "typing.Any"
140140
assert typenames(MyClass, config=config) == "MyClass"
141141
assert typenames(OtherModuleClass, config=config) == "other_module.OtherModuleClass"
142142
assert typenames(FnScopeClass, config=config) == "test_remove_modules.<locals>.FnScopeClass"
143143

144144
# Add to defaults
145-
config = TypenamesConfig(remove_modules=DEFAULT_REMOVE_MODULES + ["tests"])
145+
config = TypenamesConfig(remove_modules=DEFAULT_REMOVE_MODULES + ["test_typenames"])
146146
assert typenames(typing.Any, config=config) == "Any"
147147
assert typenames(MyClass, config=config) == "MyClass"
148148
assert typenames(OtherModuleClass, config=config) == "other_module.OtherModuleClass"
@@ -278,15 +278,19 @@ def test_node_repr():
278278

279279

280280
@pytest.mark.parametrize(
281-
"case", is_union_special_form_cases, ids=[str(c[0]) for c in is_union_special_form_cases]
281+
"case",
282+
is_union_special_form_cases,
283+
ids=[str(c[0]) for c in is_union_special_form_cases],
282284
)
283285
def test_is_union_special_form(case):
284286
"""Test that is_union_special_form correctly identifies if using typing.Union."""
285287
assert is_union_special_form(case[0]) == case[1]
286288

287289

288290
@pytest.mark.parametrize(
289-
"case", is_union_special_form_cases, ids=[str(c[0]) for c in is_union_special_form_cases]
291+
"case",
292+
is_union_special_form_cases,
293+
ids=[str(c[0]) for c in is_union_special_form_cases],
290294
)
291295
def test_is_union_or_operator_for_typing_alias_cases(case):
292296
"""Test that is_union_or_operator correctly returns False for all typing.Union test cases."""
@@ -305,14 +309,18 @@ def test_is_union_or_operator_for_typing_alias_cases(case):
305309
]
306310

307311
@pytest.mark.parametrize(
308-
"case", is_union_or_operator_cases, ids=[str(c[0]) for c in is_union_or_operator_cases]
312+
"case",
313+
is_union_or_operator_cases,
314+
ids=[str(c[0]) for c in is_union_or_operator_cases],
309315
)
310316
def test_is_union_or_operator(case):
311317
"""Test that is_union_or_operator correctly identifies cases using | operator."""
312318
assert is_union_or_operator(case[0]) == case[1]
313319

314320
@pytest.mark.parametrize(
315-
"case", is_union_or_operator_cases, ids=[str(c[0]) for c in is_union_or_operator_cases]
321+
"case",
322+
is_union_or_operator_cases,
323+
ids=[str(c[0]) for c in is_union_or_operator_cases],
316324
)
317325
def test_is_union_special_form_for_or_operator_cases(case):
318326
"""Test that is_union_special_form correctly returns False for all | operator cases."""

tests/typechecks.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import typing
2+
3+
from typenames import parse_type_tree, typenames
4+
5+
typenames(int)
6+
# Unions
7+
typenames(str | int)
8+
typenames(typing.Union[str, int])
9+
typenames(typing.Optional[str])
10+
# Generics
11+
typenames(dict[str, int])
12+
typenames(typing.Dict[str, int])
13+
# Other special forms
14+
typenames(typing.Any)
15+
typenames(typing.Literal["foo"])
16+
17+
parse_type_tree(int)
18+
# Unions
19+
parse_type_tree(str | int)
20+
parse_type_tree(typing.Union[str, int])
21+
parse_type_tree(typing.Optional[str])
22+
# Generics
23+
parse_type_tree(dict[str, int])
24+
parse_type_tree(typing.Dict[str, int])
25+
# Other special forms
26+
parse_type_tree(typing.Any)
27+
parse_type_tree(typing.Literal["foo"])

0 commit comments

Comments
 (0)