Repository: samuelcolvin/pydantic (python)

Issue:
Pydantic fail to parse ClassVar annotation when it's a string
### Checks

* [x] I added a descriptive title to this issue
* [x] I have searched (google, github) for similar issues and couldn't find anything
* [x] I have read and followed [the docs](https://pydantic-docs.helpmanual.io/) and still think this is a bug

<!-- Sorry to sound so draconian, but every second saved replying to issues is time spend improving pydantic :-) -->

# Bug

Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
            pydantic version: 1.8.2
            pydantic compiled: False
                 install path: /Users/yuriikarabas/my-projects/pydantic/pydantic
               python version: 3.9.8 (tags/v3.9.8:bb3fdcfe95, Nov 10 2021, 14:54:52)  [Clang 13.0.0 (clang-1300.0.29.3)]
                     platform: macOS-12.0.1-x86_64-i386-64bit
     optional deps. installed: ['devtools', 'dotenv', 'email-validator', 'typing-extensions']
```
<!-- or if you're using pydantic prior to v1.3, manually include: OS, python version and pydantic version -->

<!-- Please read the [docs](https://pydantic-docs.helpmanual.io/) and search through issues to
confirm your bug hasn't already been reported. -->

<!-- Where possible please include a self-contained code snippet describing your bug: -->

```py
from typing import ClassVar

from pydantic import BaseModel


class Model(BaseModel):
    val: "ClassVar[int]" = 10
```
```
Traceback (most recent call last):
  File "/Users/yuriikarabas/my-projects/pydantic/temp.py", line 6, in <module>
    class Model(BaseModel):
  File "/Users/yuriikarabas/my-projects/pydantic/pydantic/main.py", line 187, in __new__
    annotations = resolve_annotations(namespace.get('__annotations__', {}), namespace.get('__module__', None))
  File "/Users/yuriikarabas/my-projects/pydantic/pydantic/typing.py", line 340, in resolve_annotations
    value = _eval_type(value, base_globals, None)
  File "/Users/yuriikarabas/my-projects/cpython/Lib/typing.py", line 292, in _eval_type
    return t._evaluate(globalns, localns, recursive_guard)
  File "/Users/yuriikarabas/my-projects/cpython/Lib/typing.py", line 553, in _evaluate
    type_ = _type_check(
  File "/Users/yuriikarabas/my-projects/cpython/Lib/typing.py", line 158, in _type_check
    raise TypeError(f"{arg} is not valid as type argument")
TypeError: typing.ClassVar[int] is not valid as type argument
```


Pull request:
Fix issue with ClassVar parsing
<!-- Thank you for your contribution! -->
<!-- Unless your change is trivial, please create an issue to discuss the change before creating a PR -->
<!-- See https://pydantic-docs.helpmanual.io/contributing/ for help on Contributing -->

## Change Summary

<!-- Please give a short summary of the changes. -->

## Related issue number
Fixes #3401

<!-- Are there any issues opened that will be resolved by merging this change? -->

## Checklist

* [x] Unit tests for the changes exist
* [x] Tests pass on CI and coverage remains at 100%
* [x] Documentation reflects the changes where applicable
* [x] `changes/<pull request or issue id>-<github username>.md` file added describing change
  (see [changes/README.md](https://github.com/samuelcolvin/pydantic/blob/master/changes/README.md) for details)
* [x] My PR is ready to review, **please add a comment including the phrase "please review" to assign reviewers**


Patch:
diff --git a/changes/3401-uriyyo.md b/changes/3401-uriyyo.md
new file mode 100644
index 000000000..7b46117f5
--- /dev/null
+++ b/changes/3401-uriyyo.md
@@ -0,0 +1,1 @@
+Fix issue when pydantic fail to parse `typing.ClassVar` string type annotation.
\ No newline at end of file
diff --git a/pydantic/typing.py b/pydantic/typing.py
index 156db0b5f..5797432ec 100644
--- a/pydantic/typing.py
+++ b/pydantic/typing.py
@@ -332,7 +332,9 @@ def resolve_annotations(raw_annotations: Dict[str, Type[Any]], module_name: Opti
     annotations = {}
     for name, value in raw_annotations.items():
         if isinstance(value, str):
-            if sys.version_info >= (3, 7):
+            if (3, 10) > sys.version_info >= (3, 9, 8) or sys.version_info >= (3, 10, 1):
+                value = ForwardRef(value, is_argument=False, is_class=True)
+            elif sys.version_info >= (3, 7):
                 value = ForwardRef(value, is_argument=False)
             else:
                 value = ForwardRef(value)


Test patch:
diff --git a/tests/test_forward_ref.py b/tests/test_forward_ref.py
index 95595fcbf..692a33d2f 100644
--- a/tests/test_forward_ref.py
+++ b/tests/test_forward_ref.py
@@ -519,3 +519,20 @@ def test_nested_forward_ref():
     NestedTuple.update_forward_refs()
     obj = NestedTuple.parse_obj({'x': ('1', {'x': ('2', {'x': ('3', None)})})})
     assert obj.dict() == {'x': (1, {'x': (2, {'x': (3, None)})})}
+
+
+@skip_pre_37
+def test_class_var_as_string(create_module):
+    module = create_module(
+        # language=Python
+        """
+from __future__ import annotations
+from typing import ClassVar
+from pydantic import BaseModel
+
+class Model(BaseModel):
+    a: ClassVar[int]
+"""
+    )
+
+    assert module.Model.__class_vars__ == {'a'}