Skip to content

Commit 4b473b9

Browse files
authored
type hint update for Python 3.9 and later (#34)
1 parent 7009927 commit 4b473b9

File tree

3 files changed

+39
-44
lines changed

3 files changed

+39
-44
lines changed

example_script.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import asyncio
22
import decimal
3-
import typing as t
3+
from typing import Optional
44

55
from targ import CLI
66

@@ -49,7 +49,7 @@ def say_hello(name: str, greeting: str = "hello"):
4949
# print_address --number=1 --street="Royal Avenue" --postcode="XYZ 123"
5050
# --city=London
5151
def print_address(
52-
number: int, street: str, postcode: str, city: t.Optional[str] = None
52+
number: int, street: str, postcode: str, city: Optional[str] = None
5353
):
5454
"""
5555
Print out the full address.

targ/__init__.py

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,15 @@
66
import json
77
import sys
88
import traceback
9-
import typing as t
9+
from collections.abc import Callable
1010
from dataclasses import dataclass, field
11-
12-
try:
13-
from typing import get_args, get_origin # type: ignore
14-
except ImportError:
15-
# For Python 3.7 support
16-
from typing_extensions import get_args, get_origin # type: ignore
11+
from typing import Any, Optional, Union, get_args, get_origin, get_type_hints
1712

1813
from docstring_parser import Docstring, DocstringParam, parse # type: ignore
1914

2015
from .format import Color, format_text, get_underline
2116

22-
__VERSION__ = "0.5.0"
17+
__VERSION__ = "0.6.0"
2318

2419

2520
# If an annotation is one of these values, we will convert the string value
@@ -29,8 +24,8 @@
2924

3025
@dataclass
3126
class Arguments:
32-
args: t.List[str] = field(default_factory=list)
33-
kwargs: t.Dict[str, t.Any] = field(default_factory=dict)
27+
args: list[str] = field(default_factory=list)
28+
kwargs: dict[str, Any] = field(default_factory=dict)
3429

3530

3631
@dataclass
@@ -54,14 +49,14 @@ class Command:
5449
5550
"""
5651

57-
command: t.Callable
58-
group_name: t.Optional[str] = None
59-
command_name: t.Optional[str] = None
60-
aliases: t.List[str] = field(default_factory=list)
52+
command: Callable
53+
group_name: Optional[str] = None
54+
command_name: Optional[str] = None
55+
aliases: list[str] = field(default_factory=list)
6156

6257
def __post_init__(self) -> None:
6358
self.command_docstring: Docstring = parse(self.command.__doc__ or "")
64-
self.annotations = t.get_type_hints(self.command)
59+
self.annotations = get_type_hints(self.command)
6560
self.signature = inspect.signature(self.command)
6661
self.solo = False
6762
if not self.command_name:
@@ -85,7 +80,7 @@ def description(self) -> str:
8580
]
8681
)
8782

88-
def _get_docstring_param(self, arg_name) -> t.Optional[DocstringParam]:
83+
def _get_docstring_param(self, arg_name) -> Optional[DocstringParam]:
8984
for param in self.command_docstring.params:
9085
if param.arg_name == arg_name:
9186
return param
@@ -200,7 +195,7 @@ def call_with(self, arg_class: Arguments):
200195
self.print_help()
201196
return
202197

203-
annotations = t.get_type_hints(self.command)
198+
annotations = get_type_hints(self.command)
204199

205200
kwargs = arg_class.kwargs.copy()
206201
for index, value in enumerate(arg_class.args):
@@ -215,8 +210,8 @@ def call_with(self, arg_class: Arguments):
215210

216211
if annotation in CONVERTABLE_TYPES:
217212
value = annotation(value)
218-
elif get_origin(annotation) is t.Union: # type: ignore
219-
# t.Union is used to detect t.Optional
213+
elif get_origin(annotation) is Union: # type: ignore
214+
# Union is used to detect Optional
220215
inner_annotations = get_args(annotation)
221216
filtered = [i for i in inner_annotations if i is not None]
222217
if len(filtered) == 1:
@@ -250,7 +245,7 @@ class CLI:
250245
"""
251246

252247
description: str = "Targ CLI"
253-
commands: t.List[Command] = field(default_factory=list, init=False)
248+
commands: list[Command] = field(default_factory=list, init=False)
254249

255250
def command_exists(self, group_name: str, command_name: str) -> bool:
256251
"""
@@ -277,10 +272,10 @@ def _validate_name(self, name: str) -> bool:
277272

278273
def register(
279274
self,
280-
command: t.Callable,
281-
group_name: t.Optional[str] = None,
282-
command_name: t.Optional[str] = None,
283-
aliases: t.List[str] = [],
275+
command: Callable,
276+
group_name: Optional[str] = None,
277+
command_name: Optional[str] = None,
278+
aliases: list[str] = [],
284279
):
285280
"""
286281
Register a function or coroutine as a CLI command.
@@ -337,15 +332,15 @@ def get_help_text(self) -> str:
337332

338333
return "\n".join(lines)
339334

340-
def _get_cleaned_args(self) -> t.List[str]:
335+
def _get_cleaned_args(self) -> list[str]:
341336
"""
342337
Remove any redundant arguments.
343338
"""
344339
return sys.argv[1:]
345340

346341
def _get_command(
347-
self, command_name: str, group_name: t.Optional[str] = None
348-
) -> t.Optional[Command]:
342+
self, command_name: str, group_name: Optional[str] = None
343+
) -> Optional[Command]:
349344
for command in self.commands:
350345
if (
351346
command.command_name == command_name
@@ -356,14 +351,14 @@ def _get_command(
356351
return command
357352
return None
358353

359-
def _clean_cli_argument(self, value: str) -> t.Any:
354+
def _clean_cli_argument(self, value: str) -> Any:
360355
if value in ["True", "true", "t"]:
361356
return True
362357
elif value in ["False", "false", "f"]:
363358
return False
364359
return value
365360

366-
def _get_arg_class(self, args: t.List[str]) -> Arguments:
361+
def _get_arg_class(self, args: list[str]) -> Arguments:
367362
arguments = Arguments()
368363
for arg_str in args:
369364
if arg_str.startswith("--"):
@@ -401,7 +396,7 @@ def run(self, solo: bool = False):
401396
402397
"""
403398
cleaned_args = self._get_cleaned_args()
404-
command: t.Optional[Command] = None
399+
command: Optional[Command] = None
405400

406401
# Work out if to enable tracebacks
407402
try:

tests/test_command.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import dataclasses
22
import decimal
33
import sys
4-
import typing as t
4+
from typing import Any, Optional
55
from unittest import TestCase
66
from unittest.mock import MagicMock, patch
77

@@ -15,7 +15,7 @@ def add(a: int, b: int):
1515
print(a + b)
1616

1717

18-
def print_(value: t.Any, *args, **kwargs):
18+
def print_(value: Any, *args, **kwargs):
1919
"""
2020
When patching the builtin print statement, this is used as a side effect,
2121
so we can still use debug statements.
@@ -26,7 +26,7 @@ def print_(value: t.Any, *args, **kwargs):
2626

2727
@dataclasses.dataclass
2828
class Config:
29-
params: t.List[str]
29+
params: list[str]
3030
output: str
3131

3232

@@ -158,7 +158,7 @@ def test_command(arg1: bool = False):
158158

159159
with patch("builtins.print", side_effect=print_) as print_mock:
160160

161-
configs: t.List[Config] = [
161+
configs: list[Config] = [
162162
Config(params=["test_command"], output="arg1 is False"),
163163
Config(params=["test_command", "f"], output="arg1 is False"),
164164
Config(
@@ -209,7 +209,7 @@ def test_optional_bool_arg(self, _get_cleaned_args: MagicMock):
209209
Test command arguments which are of type Optional[bool].
210210
"""
211211

212-
def test_command(arg1: t.Optional[bool] = None):
212+
def test_command(arg1: Optional[bool] = None):
213213
"""
214214
A command for testing optional boolean arguments.
215215
"""
@@ -227,7 +227,7 @@ def test_command(arg1: t.Optional[bool] = None):
227227

228228
with patch("builtins.print", side_effect=print_) as print_mock:
229229

230-
configs: t.List[Config] = [
230+
configs: list[Config] = [
231231
Config(
232232
params=["test_command", "--arg1"],
233233
output="arg1 is True",
@@ -285,7 +285,7 @@ def test_command(arg1: decimal.Decimal):
285285

286286
with patch("builtins.print", side_effect=print_) as print_mock:
287287

288-
configs: t.List[Config] = [
288+
configs: list[Config] = [
289289
Config(
290290
params=["test_command", "1"],
291291
output="arg1 is int",
@@ -322,7 +322,7 @@ def test_command(arg1: decimal.Decimal):
322322

323323
with patch("builtins.print", side_effect=print_) as print_mock:
324324

325-
configs: t.List[Config] = [
325+
configs: list[Config] = [
326326
Config(
327327
params=["test_command", "1.11"],
328328
output="arg1 is Decimal",
@@ -359,7 +359,7 @@ def test_command(arg1: float):
359359

360360
with patch("builtins.print", side_effect=print_) as print_mock:
361361

362-
configs: t.List[Config] = [
362+
configs: list[Config] = [
363363
Config(
364364
params=["test_command", "1.11"],
365365
output="arg1 is float",
@@ -396,7 +396,7 @@ def test_command(arg1: float, arg2: bool):
396396

397397
with patch("builtins.print", side_effect=print_) as print_mock:
398398

399-
configs: t.List[Config] = [
399+
configs: list[Config] = [
400400
Config(
401401
params=["test_command", "1.11", "true"],
402402
output="arg1 is float, arg2 is bool",
@@ -435,7 +435,7 @@ def test_command():
435435

436436
with patch("builtins.print", side_effect=print_) as print_mock:
437437

438-
configs: t.List[Config] = [
438+
configs: list[Config] = [
439439
Config(params=["test_command"], output="Command called"),
440440
Config(params=["tc"], output="Command called"),
441441
]
@@ -461,7 +461,7 @@ def test_command(name):
461461

462462
with patch("builtins.print", side_effect=print_) as print_mock:
463463

464-
configs: t.List[Config] = [
464+
configs: list[Config] = [
465465
Config(params=["test_command", "hello"], output="hello"),
466466
]
467467

0 commit comments

Comments
 (0)