log21 3.4.0__tar.gz → 3.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {log21-3.4.0 → log21-3.5.0}/PKG-INFO +1 -2
- {log21-3.4.0 → log21-3.5.0}/README.md +0 -1
- {log21-3.4.0 → log21-3.5.0}/pyproject.toml +1 -1
- {log21-3.4.0 → log21-3.5.0}/src/log21/__init__.py +1 -1
- {log21-3.4.0 → log21-3.5.0}/src/log21/argumentify.py +252 -26
- {log21-3.4.0 → log21-3.5.0}/src/log21/_argparse.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/_module_helper.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/argparse.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/colors.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/crash_reporter/__init__.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/crash_reporter/formatters.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/crash_reporter/reporters.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/file_handler.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/formatters.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/helper_types.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/levels.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/logger.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/logging_window.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/manager.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/pprint.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/progress_bar.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/stream_handler.py +0 -0
- {log21-3.4.0 → log21-3.5.0}/src/log21/tree_print.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: log21
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.5.0
|
|
4
4
|
Summary: A simple logging package
|
|
5
5
|
Keywords: python,log,colorize,color,logging,Python3,CodeWriter21
|
|
6
6
|
Author: CodeWriter21(Mehrad Pooryoussof)
|
|
@@ -29,7 +29,6 @@ log21
|
|
|
29
29
|
|
|
30
30
|

|
|
31
31
|
[](https://gitlab.com/CodeWriter21/log21/-/commits/master)
|
|
32
|
-
[](https://gitlab.com/CodeWriter21/log21)
|
|
33
32
|
|
|
34
33
|
A simple logging package that helps you log colorized messages in Windows console and
|
|
35
34
|
other operating systems.
|
|
@@ -3,7 +3,6 @@ log21
|
|
|
3
3
|
|
|
4
4
|

|
|
5
5
|
[](https://gitlab.com/CodeWriter21/log21/-/commits/master)
|
|
6
|
-
[](https://gitlab.com/CodeWriter21/log21)
|
|
7
6
|
|
|
8
7
|
A simple logging package that helps you log colorized messages in Windows console and
|
|
9
8
|
other operating systems.
|
|
@@ -33,7 +33,7 @@ from .stream_handler import StreamHandler, ColorizingStreamHandler
|
|
|
33
33
|
# yapf: enable
|
|
34
34
|
|
|
35
35
|
__author__ = 'CodeWriter21 (Mehrad Pooryoussof)'
|
|
36
|
-
__version__ = '3.
|
|
36
|
+
__version__ = '3.5.0'
|
|
37
37
|
__github__ = 'https://GitHub.com/MPCodeWriter21/log21'
|
|
38
38
|
__all__ = [
|
|
39
39
|
'ColorizingStreamHandler', 'DecolorizingFileHandler', 'ColorizingFormatter',
|
|
@@ -450,18 +450,21 @@ def _normalize_exclusive_groups(
|
|
|
450
450
|
|
|
451
451
|
def _resolve_command_groups(
|
|
452
452
|
mutually_exclusive: _Any, command: _Optional[str],
|
|
453
|
-
argument_names: _Set[str]
|
|
453
|
+
argument_names: _Set[str], strict: bool = True
|
|
454
454
|
) -> _List[_Tuple[_List[str], bool]]:
|
|
455
455
|
"""Resolve which exclusive groups apply to a single command parser.
|
|
456
456
|
|
|
457
457
|
`mutually_exclusive` may be a plain list of groups (broadcast to every
|
|
458
458
|
command that defines all named parameters) or a `{command_name: groups}`
|
|
459
459
|
mapping for targeted groups. Unknown parameter names and groups that
|
|
460
|
-
match no command raise `ValueError
|
|
460
|
+
match no command raise `ValueError` (unless `strict` is disabled, in
|
|
461
|
+
which case non-matching groups are silently skipped for this command —
|
|
462
|
+
used for nested trees where a global check runs instead).
|
|
461
463
|
|
|
462
464
|
:param mutually_exclusive: The raw `mutually_exclusive` value.
|
|
463
465
|
:param command: The command name, or `None` for a single-function parser.
|
|
464
466
|
:param argument_names: The parameter names of the command.
|
|
467
|
+
:param strict: Raise when a broadcast list matches this command nowhere.
|
|
465
468
|
:raises ValueError: If a group references unknown parameters.
|
|
466
469
|
:return: The groups applying to this command.
|
|
467
470
|
"""
|
|
@@ -486,12 +489,22 @@ def _resolve_command_groups(
|
|
|
486
489
|
)
|
|
487
490
|
_check_group_overlap(groups, command)
|
|
488
491
|
return groups
|
|
492
|
+
return _resolve_broadcast_groups(
|
|
493
|
+
mutually_exclusive, command, argument_names, strict=strict
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
def _resolve_broadcast_groups(
|
|
498
|
+
mutually_exclusive: _Any, command: _Optional[str],
|
|
499
|
+
argument_names: _Set[str], strict: bool = True
|
|
500
|
+
) -> _List[_Tuple[_List[str], bool]]:
|
|
501
|
+
"""Resolve broadcast groups against one command's parameters."""
|
|
489
502
|
groups = _normalize_exclusive_groups(mutually_exclusive)
|
|
490
503
|
applicable = [
|
|
491
504
|
group for group in groups
|
|
492
505
|
if all(name in argument_names for name in group[0])
|
|
493
506
|
]
|
|
494
|
-
if groups and not applicable:
|
|
507
|
+
if strict and groups and not applicable:
|
|
495
508
|
# A broadcast list that matches nowhere is almost certainly a typo:
|
|
496
509
|
# fail fast instead of silently ignoring it.
|
|
497
510
|
missing = [
|
|
@@ -678,12 +691,204 @@ def _argumentify_one(
|
|
|
678
691
|
parser.error(error.message)
|
|
679
692
|
|
|
680
693
|
|
|
694
|
+
def _normalize_command_node(node: _Any, path: _Tuple[str, ...] = ()) -> _Dict[str, _Any]:
|
|
695
|
+
"""Validate an entry-point node and normalize it to a command tree.
|
|
696
|
+
|
|
697
|
+
Leaves are callables, inner nodes are (possibly nested) mappings or lists
|
|
698
|
+
of callables. Returns `{name: callable-or-mapping}` with lists converted
|
|
699
|
+
to mappings keyed by function name.
|
|
700
|
+
|
|
701
|
+
:param node: The mapping, list or callable to normalize.
|
|
702
|
+
:param path: The dotted path of `node` within the tree (for errors).
|
|
703
|
+
:raises TypeError: If a value is neither a function nor a mapping/list.
|
|
704
|
+
:raises ValueError: If a group defines no subcommands.
|
|
705
|
+
:return: The normalized `{name: ...}` mapping.
|
|
706
|
+
"""
|
|
707
|
+
label = '.'.join(path) if path else '<root>'
|
|
708
|
+
if isinstance(node, _List):
|
|
709
|
+
normalized: _Dict[str, _Any] = {}
|
|
710
|
+
for func in node:
|
|
711
|
+
if not callable(func):
|
|
712
|
+
raise TypeError(
|
|
713
|
+
"argumentify: func must be a function or a list of functions or a "
|
|
714
|
+
"dictionary of functions."
|
|
715
|
+
)
|
|
716
|
+
normalized[func.__name__] = func
|
|
717
|
+
return normalized
|
|
718
|
+
if isinstance(node, _Dict):
|
|
719
|
+
normalized = {}
|
|
720
|
+
for name, child in node.items():
|
|
721
|
+
if callable(child):
|
|
722
|
+
normalized[name] = child
|
|
723
|
+
elif isinstance(child, (_Dict, _List)):
|
|
724
|
+
sub = _normalize_command_node(child, (*path, name))
|
|
725
|
+
if not sub:
|
|
726
|
+
raise ValueError(
|
|
727
|
+
f'Command group {".".join((*path, name))!r} defines '
|
|
728
|
+
'no subcommands.'
|
|
729
|
+
)
|
|
730
|
+
normalized[name] = sub
|
|
731
|
+
else:
|
|
732
|
+
raise TypeError(
|
|
733
|
+
"argumentify: func must be a function or a list of functions or a "
|
|
734
|
+
"dictionary of functions."
|
|
735
|
+
)
|
|
736
|
+
return normalized
|
|
737
|
+
raise TypeError(
|
|
738
|
+
"argumentify: func must be a function or a list of functions or a "
|
|
739
|
+
f"dictionary of functions (got {label!r})."
|
|
740
|
+
)
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
def _collect_leaves(
|
|
744
|
+
node: _Dict[str, _Any], path: _Tuple[str, ...] = ()
|
|
745
|
+
) -> _List[_Tuple[str, str, Callable]]:
|
|
746
|
+
"""Collect `(dotted_path, name, function)` leaves of a command tree."""
|
|
747
|
+
leaves: _List[_Tuple[str, str, Callable]] = []
|
|
748
|
+
for name, child in node.items():
|
|
749
|
+
if callable(child):
|
|
750
|
+
leaves.append(('.'.join((*path, name)), name, child))
|
|
751
|
+
else:
|
|
752
|
+
leaves.extend(_collect_leaves(child, (*path, name)))
|
|
753
|
+
return leaves
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
def _validate_mutex_keys(mutually_exclusive: _Any, leaf_paths: _List[str]) -> None:
|
|
757
|
+
"""Reject mutex mapping keys that match no leaf command.
|
|
758
|
+
|
|
759
|
+
Keys may be full dotted paths (`"metadata.edit"`) or plain leaf names
|
|
760
|
+
(`"edit"`).
|
|
761
|
+
|
|
762
|
+
:param mutually_exclusive: The raw `mutually_exclusive` value.
|
|
763
|
+
:param leaf_paths: Dotted paths of all leaf commands.
|
|
764
|
+
:raises ValueError: If a key matches nothing.
|
|
765
|
+
"""
|
|
766
|
+
if not isinstance(mutually_exclusive, _Dict):
|
|
767
|
+
return
|
|
768
|
+
leaf_names = {path.split('.')[-1] for path in leaf_paths}
|
|
769
|
+
for key in mutually_exclusive:
|
|
770
|
+
if key in leaf_paths or key in leaf_names:
|
|
771
|
+
continue
|
|
772
|
+
raise ValueError(
|
|
773
|
+
f'mutually_exclusive references unknown command {key!r} '
|
|
774
|
+
f'(known commands: {sorted(leaf_paths)}).'
|
|
775
|
+
)
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
def _resolve_leaf_groups(
|
|
779
|
+
mutually_exclusive: _Any, dotted: str, leaf: str, argument_names: _Set[str],
|
|
780
|
+
leaf_paths: _List[str]
|
|
781
|
+
) -> _List[_Tuple[_List[str], bool]]:
|
|
782
|
+
"""Resolve the exclusive groups applying to one leaf command.
|
|
783
|
+
|
|
784
|
+
Plain lists broadcast to every leaf defining all named parameters. For
|
|
785
|
+
mappings, an exact dotted-path key wins; otherwise a leaf-name key
|
|
786
|
+
applies when it is unique across the tree (ambiguous leaf names raise
|
|
787
|
+
`ValueError` suggesting dotted paths).
|
|
788
|
+
|
|
789
|
+
:param mutually_exclusive: The raw `mutually_exclusive` value.
|
|
790
|
+
:param dotted: The dotted path of the leaf (e.g. `"metadata.edit"`).
|
|
791
|
+
:param leaf: The leaf command name.
|
|
792
|
+
:param argument_names: The parameter names of the leaf.
|
|
793
|
+
:param leaf_paths: Dotted paths of all leaf commands.
|
|
794
|
+
:raises ValueError: If a group references unknown parameters.
|
|
795
|
+
:return: The groups applying to this leaf.
|
|
796
|
+
"""
|
|
797
|
+
if mutually_exclusive is None:
|
|
798
|
+
return []
|
|
799
|
+
if isinstance(mutually_exclusive, _Dict):
|
|
800
|
+
if dotted in mutually_exclusive:
|
|
801
|
+
raw = mutually_exclusive[dotted]
|
|
802
|
+
elif leaf in mutually_exclusive:
|
|
803
|
+
same = sorted(p for p in leaf_paths if p.split('.')[-1] == leaf)
|
|
804
|
+
if len(same) > 1:
|
|
805
|
+
raise ValueError(
|
|
806
|
+
f'Mutually exclusive key {leaf!r} is ambiguous between '
|
|
807
|
+
f'commands {same}; use dotted paths instead.'
|
|
808
|
+
)
|
|
809
|
+
raw = mutually_exclusive[leaf]
|
|
810
|
+
else:
|
|
811
|
+
return []
|
|
812
|
+
groups = _normalize_exclusive_groups(raw)
|
|
813
|
+
for names, _ in groups:
|
|
814
|
+
unknown = [name for name in names if name not in argument_names]
|
|
815
|
+
if unknown:
|
|
816
|
+
raise ValueError(
|
|
817
|
+
f'Mutually exclusive group {names!r} references unknown '
|
|
818
|
+
f'parameters of command {dotted!r}: {unknown!r}'
|
|
819
|
+
)
|
|
820
|
+
_check_group_overlap(groups, dotted)
|
|
821
|
+
return groups
|
|
822
|
+
return _resolve_broadcast_groups(
|
|
823
|
+
mutually_exclusive, dotted, argument_names, strict=False
|
|
824
|
+
)
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
def _validate_broadcast_groups(
|
|
828
|
+
mutually_exclusive: _Any, leaf_infos: _Dict[str, FunctionInfo]
|
|
829
|
+
) -> None:
|
|
830
|
+
"""Reject broadcast groups that match no leaf command at all.
|
|
831
|
+
|
|
832
|
+
Called once per tree (nested parsers skip non-matching groups silently,
|
|
833
|
+
so without this a typo'd group would vanish without a trace).
|
|
834
|
+
|
|
835
|
+
:param mutually_exclusive: The raw `mutually_exclusive` value.
|
|
836
|
+
:param leaf_infos: `{dotted_path: FunctionInfo}` for every leaf.
|
|
837
|
+
:raises ValueError: If a group matches nowhere.
|
|
838
|
+
"""
|
|
839
|
+
if mutually_exclusive is None or isinstance(mutually_exclusive, _Dict):
|
|
840
|
+
return
|
|
841
|
+
arg_sets = [set(info.arguments) for info in leaf_infos.values()]
|
|
842
|
+
for names, _ in _normalize_exclusive_groups(mutually_exclusive):
|
|
843
|
+
if not any(all(name in arg_set for name in names) for arg_set in arg_sets):
|
|
844
|
+
raise ValueError(
|
|
845
|
+
f'Mutually exclusive group {names!r} matches no command.'
|
|
846
|
+
)
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
def _add_command_level(
|
|
850
|
+
subparsers: _Any,
|
|
851
|
+
node: _Dict[str, _Any],
|
|
852
|
+
path: _Tuple[str, ...],
|
|
853
|
+
leaf_infos: _Dict[str, FunctionInfo],
|
|
854
|
+
mutually_exclusive: _Any = None,
|
|
855
|
+
leaf_paths: _Optional[_List[str]] = None
|
|
856
|
+
) -> None:
|
|
857
|
+
"""Add one command-tree level to a subparsers action (recursively).
|
|
858
|
+
|
|
859
|
+
Leaf commands get annotation-driven arguments (plus any applicable
|
|
860
|
+
mutually exclusive groups); group nodes get a nested `add_subparsers`
|
|
861
|
+
level of their own, so `prog group --help` lists the group's commands.
|
|
862
|
+
"""
|
|
863
|
+
for name, child in node.items():
|
|
864
|
+
if callable(child):
|
|
865
|
+
dotted = '.'.join((*path, name))
|
|
866
|
+
info = leaf_infos[dotted]
|
|
867
|
+
subparser = subparsers.add_parser(name, help=info.docstring.description)
|
|
868
|
+
groups = _resolve_leaf_groups(
|
|
869
|
+
mutually_exclusive, dotted, name, set(info.arguments),
|
|
870
|
+
leaf_paths or [dotted]
|
|
871
|
+
)
|
|
872
|
+
_add_arguments(subparser, info, exclusive_groups=groups)
|
|
873
|
+
subparser.set_defaults(func=info.function)
|
|
874
|
+
else:
|
|
875
|
+
group_parser = subparsers.add_parser(name)
|
|
876
|
+
nested = group_parser.add_subparsers(required=True)
|
|
877
|
+
_add_command_level(
|
|
878
|
+
nested, child, (*path, name), leaf_infos, mutually_exclusive,
|
|
879
|
+
leaf_paths
|
|
880
|
+
)
|
|
881
|
+
|
|
882
|
+
|
|
681
883
|
def _argumentify(
|
|
682
|
-
functions: _Dict[str,
|
|
884
|
+
functions: _Dict[str, _Any], mutually_exclusive: _Any = None
|
|
683
885
|
) -> None:
|
|
684
886
|
"""This function argumentifies one or more functions as the entry point of the
|
|
685
887
|
script.
|
|
686
888
|
|
|
889
|
+
`functions` is a command tree: values are either callables (leaf commands)
|
|
890
|
+
or nested mappings/lists (command groups), at any depth.
|
|
891
|
+
|
|
687
892
|
:param functions: A dictionary of functions to argumentify.
|
|
688
893
|
:param mutually_exclusive: A list of mutually exclusive groups broadcast
|
|
689
894
|
to every command defining all named parameters, or a
|
|
@@ -692,33 +897,39 @@ def _argumentify(
|
|
|
692
897
|
mapping.
|
|
693
898
|
:raises RuntimeError:
|
|
694
899
|
"""
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
900
|
+
tree = _normalize_command_node(functions)
|
|
901
|
+
if not tree:
|
|
902
|
+
raise ValueError('argumentify: no entry points defined.')
|
|
903
|
+
leaves = _collect_leaves(tree)
|
|
904
|
+
leaf_infos: _Dict[str, FunctionInfo] = {}
|
|
905
|
+
ordered: _List[_Tuple[Callable, FunctionInfo]] = []
|
|
906
|
+
for dotted, name, function in leaves:
|
|
907
|
+
info = FunctionInfo(function)
|
|
908
|
+
leaf_infos[dotted] = info
|
|
698
909
|
|
|
699
910
|
# Check if the function has a VAR_KEYWORD argument
|
|
700
911
|
# Raises a ArgumentTypeError if it does
|
|
701
|
-
for argument in
|
|
912
|
+
for argument in info.arguments.values():
|
|
702
913
|
if argument.kind == _inspect._ParameterKind.VAR_KEYWORD:
|
|
703
914
|
raise ArgumentTypeError(
|
|
704
|
-
f"Function {
|
|
915
|
+
f"Function {dotted} has `**{argument.name}` argument, "
|
|
705
916
|
"which is not supported.",
|
|
706
917
|
unsupported_arg=argument.name
|
|
707
918
|
)
|
|
919
|
+
ordered.append((function, info))
|
|
708
920
|
parser = _argparse.ColorizingArgumentParser()
|
|
709
921
|
subparsers = parser.add_subparsers(required=True)
|
|
710
|
-
for
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
)
|
|
715
|
-
|
|
716
|
-
subparser.set_defaults(func=info.function)
|
|
922
|
+
leaf_paths = [dotted for dotted, _, _ in leaves]
|
|
923
|
+
_validate_mutex_keys(mutually_exclusive, leaf_paths)
|
|
924
|
+
_validate_broadcast_groups(mutually_exclusive, leaf_infos)
|
|
925
|
+
_add_command_level(
|
|
926
|
+
subparsers, tree, (), leaf_infos, mutually_exclusive, leaf_paths
|
|
927
|
+
)
|
|
717
928
|
cli_args = parser.parse_args()
|
|
718
929
|
args = []
|
|
719
930
|
kwargs = {}
|
|
720
931
|
info = None
|
|
721
|
-
for
|
|
932
|
+
for function, info in ordered:
|
|
722
933
|
if function == cli_args.func:
|
|
723
934
|
break
|
|
724
935
|
else:
|
|
@@ -742,9 +953,9 @@ def _argumentify(
|
|
|
742
953
|
|
|
743
954
|
|
|
744
955
|
def argumentify(
|
|
745
|
-
entry_point: _Union[Callable, _List[Callable], _Dict[str,
|
|
956
|
+
entry_point: _Union[Callable, _List[Callable], _Dict[str, _Any]],
|
|
746
957
|
mutually_exclusive: _Optional[_Any] = None
|
|
747
|
-
) -> _Union[Callable, _List[Callable], _Dict[str,
|
|
958
|
+
) -> _Union[Callable, _List[Callable], _Dict[str, _Any]]:
|
|
748
959
|
"""This function argumentifies one or more functions as the entry point of the
|
|
749
960
|
script.
|
|
750
961
|
|
|
@@ -787,7 +998,9 @@ def argumentify(
|
|
|
787
998
|
|
|
788
999
|
For multiple entry points, pass a `{command_name: groups}` mapping, or a
|
|
789
1000
|
plain list of groups which applies to every command defining all named
|
|
790
|
-
parameters.
|
|
1001
|
+
parameters. With nested commands, mapping keys may be dotted paths
|
|
1002
|
+
(`"metadata.edit"`) or — when unique across the tree — plain leaf names.
|
|
1003
|
+
Positional parameters in a group accept zero values (single
|
|
791
1004
|
ones behave like `nargs='?'`, multi-value ones like `nargs='*'`) and
|
|
792
1005
|
receive their default (or `None`) when omitted; pass
|
|
793
1006
|
`{"names": [...], "required": True}` when exactly one of them must be
|
|
@@ -798,6 +1011,25 @@ def argumentify(
|
|
|
798
1011
|
mutually_exclusive={"run-recipe": [["recipe_path", "builtin"]]},
|
|
799
1012
|
)
|
|
800
1013
|
|
|
1014
|
+
Related commands can be grouped under a group verb by nesting mappings
|
|
1015
|
+
(to any depth), giving `git`-style `prog <group> <action>` interfaces
|
|
1016
|
+
where each level gets its own subcommands and `--help`:
|
|
1017
|
+
|
|
1018
|
+
argumentify({
|
|
1019
|
+
"bundle": bundle_entry_point,
|
|
1020
|
+
"metadata": {
|
|
1021
|
+
"show": show_entry_point,
|
|
1022
|
+
"clear": clear_entry_point,
|
|
1023
|
+
"edit": edit_entry_point,
|
|
1024
|
+
},
|
|
1025
|
+
})
|
|
1026
|
+
|
|
1027
|
+
$ pdf-helper metadata edit in.pdf out.pdf --title "Report"
|
|
1028
|
+
|
|
1029
|
+
Group nodes take no function: nothing executes until a leaf command is
|
|
1030
|
+
chosen. A list of functions may be used wherever a mapping is expected;
|
|
1031
|
+
empty groups raise `ValueError`.
|
|
1032
|
+
|
|
801
1033
|
:param entry_point: The function(s) to argumentify.
|
|
802
1034
|
:param mutually_exclusive: Mutually exclusive parameter groups.
|
|
803
1035
|
:raises TypeError: A function must be a function or a list of functions or a
|
|
@@ -819,12 +1051,6 @@ def argumentify(
|
|
|
819
1051
|
)
|
|
820
1052
|
functions[func.__name__] = func
|
|
821
1053
|
elif isinstance(entry_point, _Dict):
|
|
822
|
-
for func in entry_point.values():
|
|
823
|
-
if not callable(func):
|
|
824
|
-
raise TypeError(
|
|
825
|
-
"argumentify: func must be a function or a list of functions or a "
|
|
826
|
-
"dictionary of functions."
|
|
827
|
-
)
|
|
828
1054
|
functions = entry_point
|
|
829
1055
|
else:
|
|
830
1056
|
raise TypeError(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|