diff --git a/HISTORY.rst b/HISTORY.rst index 400b0fb..05d0af0 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -9,6 +9,7 @@ v0.23 (unreleased) * improve README.rst to include essential information about the package, #446 by @pilosus * ``IntEnum`` support, #444 by @potykion * fix ``ForwardRef`` collection bug, #450 by @tigerwings +* Support specialized ``ClassVars``, #455 by @tyrylu v0.22 (2019-03-29) .................... diff --git a/pydantic/main.py b/pydantic/main.py index d1de805..164d776 100644 --- a/pydantic/main.py +++ b/pydantic/main.py @@ -11,7 +11,6 @@ from typing import ( TYPE_CHECKING, Any, Callable, - ClassVar, Dict, Generator, List, @@ -38,6 +37,7 @@ from .utils import ( AnyType, ForwardRef, change_exception, + is_classvar, resolve_annotations, truncate, validate_field_name, @@ -167,7 +167,7 @@ class MetaModel(ABCMeta): class_vars = set() # annotation only fields need to come first in fields for ann_name, ann_type in annotations.items(): - if ann_type == ClassVar: + if is_classvar(ann_type): class_vars.add(ann_name) elif not ann_name.startswith('_') and ann_name not in namespace: validate_field_name(bases, ann_name) diff --git a/pydantic/utils.py b/pydantic/utils.py index 35c5ef9..fae2e06 100644 --- a/pydantic/utils.py +++ b/pydantic/utils.py @@ -7,7 +7,7 @@ from functools import lru_cache from importlib import import_module from textwrap import dedent from typing import _eval_type # type: ignore -from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional, Pattern, Tuple, Type, Union +from typing import TYPE_CHECKING, Any, ClassVar, Dict, Generator, List, Optional, Pattern, Tuple, Type, Union from . import errors @@ -268,3 +268,11 @@ def resolve_annotations(raw_annotations: Dict[str, AnyType], module_name: Option def is_callable_type(type_: AnyType) -> bool: return type_ is Callable or getattr(type_, '__origin__', None) is Callable + + +def _check_classvar(v: AnyType) -> bool: + return type(v) == type(ClassVar) and (sys.version_info < (3, 7) or getattr(v, '_name', None) == 'ClassVar') + + +def is_classvar(ann_type: AnyType) -> bool: + return _check_classvar(ann_type) or _check_classvar(getattr(ann_type, '__origin__', None)) diff --git a/tests/test_main.py b/tests/test_main.py index 48870ef..d157bdd 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -516,7 +516,7 @@ def test_value_field_name_shadows_attribute(): def test_class_var(): class MyModel(BaseModel): a: ClassVar - b: ClassVar = 1 + b: ClassVar[int] = 1 c: int = 2 assert list(MyModel.__fields__.keys()) == ['c']