diff --git a/tap/tap.py b/tap/tap.py index b4417c1..06ac096 100644 --- a/tap/tap.py +++ b/tap/tap.py @@ -9,7 +9,7 @@ import sys import time from types import MethodType -from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, TypeVar, Union, get_type_hints +from typing import Any, Callable, ClassVar, Dict, List, Optional, Sequence, Set, Tuple, TypeVar, Union, get_type_hints from typing_inspect import is_literal_type from warnings import warn @@ -169,13 +169,21 @@ def _add_argument(self, *name_or_flags, **kwargs) -> None: # Description if variable in self.class_variables: - kwargs['help'] += ' ' + self.class_variables[variable]['comment'] + comment = self.class_variables[variable]['comment'] + # Ignore attributes with comment starting with "tap: ignore" + if comment.startswith('tap: ignore'): + return + kwargs['help'] += ' ' + comment # Set other kwargs where not provided if variable in self._annotations: # Get type annotation var_type = self._annotations[variable] + # Ignore attributes with type ClassVar + if get_origin(var_type) == ClassVar: + return + # If type is not explicitly provided, set it if it's one of our supported default types if 'type' not in kwargs: # Unbox Union[type] (Optional[type]) and set var_type = type diff --git a/tap/utils.py b/tap/utils.py index c5d3f10..4ecf2b2 100644 --- a/tap/utils.py +++ b/tap/utils.py @@ -15,6 +15,7 @@ from typing import ( Any, Callable, + ClassVar, Dict, Generator, Iterator, @@ -495,6 +496,10 @@ def get_origin(tp: Any) -> Any: if origin is None: origin = tp + # fix typing_inspect not supporting ClassVar + if hasattr(tp, '__origin__') and tp.__origin__ == ClassVar: + origin = ClassVar + if sys.version_info >= (3, 10) and isinstance(origin, UnionType): origin = UnionType diff --git a/tests/test_integration.py b/tests/test_integration.py index 3f2ae3a..5cffadb 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -6,7 +6,7 @@ from re import L import sys from tempfile import TemporaryDirectory -from typing import Any, Iterable, List, Optional, Set, Tuple, Union +from typing import Any, ClassVar, Iterable, List, Optional, Set, Tuple, Union from typing_extensions import Literal import unittest from unittest import TestCase @@ -328,6 +328,8 @@ class IntegrationDefaultTap(Tap): # TODO: move these elsewhere since we don't support them as defaults # arg_other_type_required: Person # arg_other_type_default: Person = Person('tap') + arg_classvar: ClassVar[str] + arg_ignore: str # tap: ignore class SubclassTests(TestCase): @@ -401,6 +403,9 @@ def test_get_default_args(self) -> None: self.assertEqual(args.arg_tuple_bool, (True, True, True, False)) self.assertEqual(args.arg_tuple_multi, (1.2, 1, 'hi', True, 1.3)) + self.assertEqual(hasattr(args, 'arg_classvar'), False) + self.assertEqual(hasattr(args, 'arg_ignore'), False) + def test_set_default_args(self) -> None: arg_untyped = 'yes' arg_str = 'goodbye'