Skip to content

Commit 77de187

Browse files
committed
edits for coverage
1 parent e8126ab commit 77de187

File tree

2 files changed

+77
-67
lines changed

2 files changed

+77
-67
lines changed

django_typer/__init__.py

Lines changed: 59 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -723,27 +723,25 @@ def _cache_initializer(
723723
cls: t.Type[DTGroup] = DTGroup,
724724
**kwargs,
725725
):
726-
if not hasattr(callback, _CACHE_KEY):
727-
728-
def register(
729-
cmd: "TyperCommand",
730-
_name: t.Optional[str] = Default(None),
731-
_help: t.Optional[str] = Default(None),
726+
def register(
727+
cmd: "TyperCommand",
728+
_name: t.Optional[str] = Default(None),
729+
_help: t.Optional[str] = Default(None),
730+
**extra,
731+
):
732+
return cmd.typer_app.callback(
733+
name=name or _name,
734+
cls=type(
735+
"_Initializer",
736+
(cls,),
737+
{"django_command": cmd, "common_init": common_init},
738+
),
739+
help=cmd.typer_app.info.help or help or _help,
740+
**kwargs,
732741
**extra,
733-
):
734-
return cmd.typer_app.callback(
735-
name=name or _name,
736-
cls=type(
737-
"_Initializer",
738-
(cls,),
739-
{"django_command": cmd, "common_init": common_init},
740-
),
741-
help=cmd.typer_app.info.help or help or _help,
742-
**kwargs,
743-
**extra,
744-
)(_strip_static(callback))
742+
)(_strip_static(callback))
745743

746-
setattr(callback, _CACHE_KEY, register)
744+
setattr(callback, _CACHE_KEY, register)
747745

748746

749747
def _cache_command(
@@ -753,23 +751,21 @@ def _cache_command(
753751
cls: t.Type[DTCommand] = DTCommand,
754752
**kwargs,
755753
):
756-
if not hasattr(callback, _CACHE_KEY):
757-
758-
def register(
759-
cmd: "TyperCommand",
760-
_name: t.Optional[str] = None,
761-
_help: t.Optional[str] = None,
754+
def register(
755+
cmd: "TyperCommand",
756+
_name: t.Optional[str] = None,
757+
_help: t.Optional[str] = None,
758+
**extra,
759+
):
760+
return cmd.typer_app.command(
761+
name=name or _name,
762+
cls=type("_Command", (cls,), {"django_command": cmd}),
763+
help=help or _help or None,
764+
**kwargs,
762765
**extra,
763-
):
764-
return cmd.typer_app.command(
765-
name=name or _name,
766-
cls=type("_Command", (cls,), {"django_command": cmd}),
767-
help=help or _help or None,
768-
**kwargs,
769-
**extra,
770-
)(_strip_static(callback))
766+
)(_strip_static(callback))
771767

772-
setattr(callback, _CACHE_KEY, register)
768+
setattr(callback, _CACHE_KEY, register)
773769

774770

775771
def _get_direct_function(
@@ -813,8 +809,8 @@ class Command(
813809

814810
if sys.version_info < (3, 9):
815811
# this is a workaround for a bug in python 3.8 that causes multiple
816-
# values for cls error. 3.8 support is sunsetting soon so we just punt
817-
# on this one - REMOVE in next version
812+
# values for cls error. 3.8 support is sun setting soon so we just punt
813+
# on this one - REMOVE when 3.8 support is dropped
818814
kwargs.pop("cls", None)
819815
return super().__call__(*args, **kwargs)
820816

@@ -861,11 +857,6 @@ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
861857
return _get_direct_function(cmd, self)(*args, **kwargs)
862858
return super().__call__(*args, **kwargs)
863859

864-
@t.overload # pragma: no cover
865-
def __get__(
866-
self, obj: "TyperCommand", owner: t.Type["TyperCommand"]
867-
) -> "Typer[P, R]": ...
868-
869860
@t.overload # pragma: no cover
870861
def __get__(
871862
self, obj: "TyperCommandMeta", owner: t.Type["TyperCommandMeta"]
@@ -888,7 +879,7 @@ def __get__(
888879
@t.overload # pragma: no cover
889880
def __get__(
890881
self, obj: "TyperCommand", owner: t.Any = None
891-
) -> MethodType: # t.Union[MethodType, t.Callable[P, R]]
882+
) -> "Typer[P, R]": # t.Union[MethodType, t.Callable[P, R]]
892883
# todo - we could return the generic callable type here but the problem
893884
# is self is included in the ParamSpec and it seems tricky to remove?
894885
# MethodType loses the parameters but is preferable to type checking errors
@@ -913,18 +904,18 @@ def __getattr__(self, name: str) -> t.Any:
913904
cmd_obj = self.cmd_obj()
914905
for cmd in self.registered_commands:
915906
assert cmd.callback
916-
if name in [cmd.callback.__name__, cmd.name]:
907+
if name in (cmd.callback.__name__, cmd.name):
917908
if cmd_obj:
918909
return _get_direct_function(cmd_obj, cmd)
919910
return cmd
920911
for grp in self.registered_groups:
921912
cmd_grp = t.cast(Typer, grp.typer_instance)
922913
assert cmd_grp
923-
if name in [
914+
if name in (
924915
cmd_grp.name,
925916
grp.name,
926917
getattr(cmd_grp.info.callback, "__name__", None),
927-
]:
918+
):
928919
return cmd_grp
929920
raise AttributeError(
930921
"{cls} object has no attribute {name}".format(
@@ -1024,8 +1015,11 @@ def __init__(
10241015
self.registered_callback = typer_app.registered_callback
10251016
self.registered_commands = copy(typer_app.registered_commands)
10261017
self.registered_groups = deepcopy(typer_app.registered_groups)
1027-
if isinstance(self.rich_help_panel, DefaultPlaceholder):
1028-
self.rich_help_panel = typer_app.rich_help_panel # type: ignore[unreachable]
1018+
self.rich_help_panel = (
1019+
typer_app.rich_help_panel
1020+
if isinstance(self.rich_help_panel, DefaultPlaceholder)
1021+
else self.rich_help_panel
1022+
)
10291023
for param, cfg in vars(self.info).items():
10301024
if isinstance(cfg, DefaultPlaceholder):
10311025
setattr(self.info, param, getattr(typer_app.info, param))
@@ -1775,10 +1769,9 @@ def depth_first_match(
17751769
for grp in reversed(app.registered_groups):
17761770
assert grp.typer_instance
17771771
grp_app = t.cast(Typer, grp.typer_instance)
1778-
if grp.typer_instance:
1779-
found = depth_first_match(grp_app, name)
1780-
if found:
1781-
return found
1772+
found = depth_first_match(grp_app, name)
1773+
if found:
1774+
return found
17821775
return None
17831776

17841777

@@ -2999,22 +2992,21 @@ def __getattr__(self, name: str) -> t.Any:
29992992
and return that command or group if the attribute name matches the command/group
30002993
function OR its registered CLI name.
30012994
"""
3002-
if name != "typer_app" and self.typer_app:
3003-
init = getattr(
3004-
self.typer_app.registered_callback,
3005-
"callback",
3006-
self.typer_app.info.callback,
3007-
)
3008-
if init and init and name == init.__name__:
3009-
return MethodType(init, self) if is_method(init) else staticmethod(init)
3010-
found = depth_first_match(self.typer_app, name)
3011-
if found:
3012-
if isinstance(found, Typer):
3013-
# todo shouldn't be needed
3014-
found._local.object = self
3015-
else:
3016-
return _get_direct_function(self, found)
3017-
return found
2995+
init = getattr(
2996+
self.typer_app.registered_callback,
2997+
"callback",
2998+
self.typer_app.info.callback,
2999+
)
3000+
if init and init and name == init.__name__:
3001+
return MethodType(init, self) if is_method(init) else staticmethod(init)
3002+
found = depth_first_match(self.typer_app, name)
3003+
if found:
3004+
if isinstance(found, Typer):
3005+
# todo shouldn't be needed
3006+
found._local.object = self
3007+
else:
3008+
return _get_direct_function(self, found)
3009+
return found
30183010
raise AttributeError(
30193011
"{cls} object has no attribute {name}".format(
30203012
cls=self.__class__.__name__, name=name

django_typer/tests/test_interface.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,3 +261,21 @@ def test_action_nargs(self):
261261
self.assertEqual(multi_parser._actions[7].nargs, -1)
262262
self.assertEqual(multi_parser._actions[8].param.name, "flag1")
263263
self.assertEqual(multi_parser._actions[8].nargs, 0)
264+
265+
def test_cmd_getattr(self):
266+
from django_typer.tests.apps.test_app.management.commands.groups import (
267+
Command as Groups,
268+
)
269+
270+
self.assertIsInstance(Groups.math.divide, typer.models.CommandInfo)
271+
try:
272+
Groups.does_not_exist
273+
self.assertFalse(True, "should have thrown AttributeError")
274+
except AttributeError as e:
275+
pass
276+
277+
try:
278+
Groups.math.does_not_exist
279+
self.assertFalse(True, "should have thrown AttributeError")
280+
except AttributeError as e:
281+
pass

0 commit comments

Comments
 (0)