Repository: RobertCraigie/pytest-pyright (language: python)

Issue:
Tests are failing
I cloned this repository and ran `tox`, and it seems like the tests failed:
```
tests/test_formatting.py ..  
tests/test_plugin.py ..FF.FFFF..

[snip]

py37: SKIP (0.03 seconds)
py38: SKIP (0.01 seconds)
py39: FAIL code 1 (15.66=setup[7.52]+cmd[8.14] seconds)
py310: SKIP (0.01 seconds)
docs: OK (7.72=setup[3.74]+cmd[3.98] seconds)
pypy3: SKIP (0.01 seconds)
lint: FAIL code 1 (6.73=setup[3.77]+cmd[0.85,2.12] seconds)
evaluation failed :( (30.36 seconds)
```

I'm on macOS 13.3.1. I'm not very familiar with `tox`, but it seems like it sets up its own environment so it shouldn't be anything related to my Python environment, right?

Here's the output of the first failing test:
```
================================================================================================================= FAILURES =================================================================================================================
____________________________________________________________________________________________________ test_reveal_type_incorrect_comment ____________________________________________________________________________________________________

pytester = <Pytester PosixPath('/private/var/folders/t6/lff4nkz567qcb589_dpx3s000000gn/T/pytest-of-gsgx/pytest-1/test_reveal_type_incorrect_comment0')>

    def test_reveal_type_incorrect_comment(pytester: Pytester) -> None:
        content = '''
        def foo(a: str) -> None:
            reveal_type(a)  # T: int
        '''
        pytester.makepyfile(**{'typesafety/bar.py': content})
        result = pytester.runpytest()
        result.assert_outcomes(failed=1)
>       result.stdout.fnmatch_lines(
            [
                '1 | def foo(a: str) -> None:',
                '2 |     reveal_type(a)  # T: int',
                'E | Expected revealed type to be "int" but got "str" instead',
                *SUMMARY_LINES,
            ],
            consecutive=True,
        )
E       Failed: nomatch: '1 | def foo(a: str) -> None:'
E           and: '=========================================================================================================== test session starts ============================================================================================================'
E           and: 'platform darwin -- Python 3.9.6, pytest-7.2.0, pluggy-1.0.0'
E           and: 'rootdir: /private/var/folders/t6/lff4nkz567qcb589_dpx3s000000gn/T/pytest-of-gsgx/pytest-1/test_reveal_type_incorrect_comment0'
E           and: 'plugins: pyright-0.0.3, syrupy-3.0.5'
E           and: 'collected 1 item'
E           and: ''
E           and: 'typesafety/bar.py F                                                                                                                                                                                                                  [100%]'
E           and: ''
E           and: '================================================================================================================= FAILURES ================================================================================================================='
E           and: '_____________________________________________________________________________________________________________ pyright: bar.py ______________________________________________________________________________________________________________'
E       exact match: '1 | def foo(a: str) -> None:'
E       exact match: '2 |     reveal_type(a)  # T: int'
E       exact match: 'E | Expected revealed type to be "int" but got "str" instead'
E       no consecutive match: '--------------------------- snapshot report summary ----------------------------'
E          with: '--------------------------------------------------------------------------------------------------------- snapshot report summary ----------------------------------------------------------------------------------------------------------'

/Users/gsgx/code/pytest-pyright/tests/test_plugin.py:67: Failed
----------------------------------------------------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------------------------------------------------
=========================================================================================================== test session starts ============================================================================================================
platform darwin -- Python 3.9.6, pytest-7.2.0, pluggy-1.0.0
rootdir: /private/var/folders/t6/lff4nkz567qcb589_dpx3s000000gn/T/pytest-of-gsgx/pytest-1/test_reveal_type_incorrect_comment0
plugins: pyright-0.0.3, syrupy-3.0.5
collected 1 item

typesafety/bar.py F                                                                                                                                                                                                                  [100%]

================================================================================================================= FAILURES =================================================================================================================
_____________________________________________________________________________________________________________ pyright: bar.py ______________________________________________________________________________________________________________
1 | def foo(a: str) -> None:
2 |     reveal_type(a)  # T: int
E | Expected revealed type to be "int" but got "str" instead
--------------------------------------------------------------------------------------------------------- snapshot report summary ----------------------------------------------------------------------------------------------------------

========================================================================================================= short test summary info ==========================================================================================================
FAILED typesafety/bar.py::bar.py
============================================================================================================ 1 failed in 0.88s =============================================================================================================
```


Discussion / hints:

Fix patch:
diff --git a/dev-requirements.txt b/dev-requirements.txt
index 14c0217..7dfd925 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -2,3 +2,4 @@ tox
 twine
 mkdocs==1.2.1
 mkdocs-material==7.1.10
+pydantic>2


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index b0f0500..1df5ff5 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -45,7 +45,7 @@ jobs:
       - name: Install dependencies
         run: |
           python -m pip install --upgrade pip
-          pip install codecov==2.1.11 -r dev-requirements.txt
+          pip install -r dev-requirements.txt
 
       - uses: actions/cache@v2
         with:
@@ -58,12 +58,6 @@ jobs:
         run: |
           tox -e setup,${{ matrix.tox-env }},report
 
-      - name: Upload coverage
-        run: |
-          codecov --file coverage.xml
-        env:
-          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
-
   lint:
     name: lint
     runs-on: ubuntu-latest
diff --git a/src/pytest_pyright/_compat.py b/src/pytest_pyright/_compat.py
new file mode 100644
index 0000000..639c997
--- /dev/null
+++ b/src/pytest_pyright/_compat.py
@@ -0,0 +1,26 @@
+from __future__ import annotations
+
+from typing import TypeVar
+
+import pydantic
+from pydantic import BaseModel
+
+
+_ModelT = TypeVar('_ModelT', bound=BaseModel)
+
+
+PYDANTIC_V2 = pydantic.VERSION.startswith('2.')
+
+
+def model_rebuild(model: type[BaseModel]) -> None:
+    if PYDANTIC_V2:
+        model.model_rebuild()
+    else:
+        model.update_forward_refs()  # pyright: ignore[reportDeprecated]
+
+
+def model_parse_json(model: type[_ModelT], obj: str | bytes) -> _ModelT:
+    if PYDANTIC_V2:
+        return model.model_validate_json(obj)
+    else:
+        return model.parse_raw(obj)  # type: ignore
diff --git a/src/pytest_pyright/models.py b/src/pytest_pyright/models.py
index 087eec5..517ffbc 100644
--- a/src/pytest_pyright/models.py
+++ b/src/pytest_pyright/models.py
@@ -5,6 +5,8 @@
 
 from pydantic import BaseModel, Field
 
+from ._compat import model_rebuild
+
 
 TYPE_ERROR_RE = re.compile(r'.*# E: (?P<expected>.*)')
 REVEAL_TYPE_RE = re.compile(r'\s+reveal_type\(.*\)\s+# T: (?P<expected>.*)')
@@ -68,7 +70,7 @@ class PyrightDiagnostic(BaseModel):
     message: str
     severity: str  # TODO: enum
     range: 'PyrightRange'
-    rule: Optional[str]
+    rule: Optional[str] = None
 
 
 class PyrightRange(BaseModel):
@@ -81,6 +83,6 @@ class PyrightRangeValue(BaseModel):
     character: int
 
 
-PyrightRange.update_forward_refs()
-PyrightResult.update_forward_refs()
-PyrightDiagnostic.update_forward_refs()
+model_rebuild(PyrightRange)
+model_rebuild(PyrightResult)
+model_rebuild(PyrightDiagnostic)
diff --git a/src/pytest_pyright/plugin.py b/src/pytest_pyright/plugin.py
index a097dee..a83cdc4 100644
--- a/src/pytest_pyright/plugin.py
+++ b/src/pytest_pyright/plugin.py
@@ -17,6 +17,7 @@
 from _pytest._code.code import TerminalRepr
 
 from .models import PyrightResult, PyrightFile
+from ._compat import model_parse_json
 
 if TYPE_CHECKING:
     from _pytest._code.code import _TracebackStyle
@@ -161,7 +162,7 @@ def runtest(self) -> None:
                 'see the captured output for more details.'
             )
 
-        result = PyrightResult.parse_raw(process.stdout)
+        result = model_parse_json(PyrightResult, process.stdout)
         absolute = str(self.path.absolute())
         errors: List[PyrightError] = []
 
@@ -268,7 +269,7 @@ class PyrightTestFile(pytest.File):
     @classmethod
     def from_parent(
         cls, *args: Any, **kwargs: Any
-    ) -> 'PyrightTestFile':  # pyright: reportIncompatibleMethodOverride=false
+    ) -> 'PyrightTestFile':  # pyright: ignore[reportIncompatibleMethodOverride]
         return cast(
             PyrightTestFile,
             super().from_parent(*args, **kwargs),
diff --git a/tests/test_plugin.py b/tests/test_plugin.py
index 8705e8d..3e4d6b5 100644
--- a/tests/test_plugin.py
+++ b/tests/test_plugin.py
@@ -10,13 +10,6 @@
     from _pytest.pytester import Pytester
 
 
-SUMMARY_LINES = [
-    '--------------------------- snapshot report summary ----------------------------',
-    '',
-    '=========================== short test summary info ============================',
-]
-
-
 @pytest.fixture(autouse=True)
 def makeconfig(pytester: Pytester) -> None:
     pytester.makefile('.json', pyrightconfig=json.dumps({'typeCheckingMode': 'strict'}))
@@ -69,7 +62,6 @@ def foo(a: str) -> None:
             '1 | def foo(a: str) -> None:',
             '2 |     reveal_type(a)  # T: int',
             'E | Expected revealed type to be "int" but got "str" instead',
-            *SUMMARY_LINES,
         ],
         consecutive=True,
     )
@@ -88,7 +80,6 @@ def foo(a: str) -> None:
             '1 | def foo(a: str) -> None:',
             '2 |     reveal_type(a)',
             'E | Missing type comment, revealed type: str',
-            *SUMMARY_LINES,
         ],
         consecutive=True,
     )
@@ -123,7 +114,6 @@ def foo(a: str) -> None:
             '3 | def foo(a: str) -> None:',
             '4 |     print(a.split(\'.\'))  # E: "split" is not a known member of "None"',
             'E | Did not raise an error',
-            *SUMMARY_LINES,
         ],
         consecutive=True,
     )
@@ -147,7 +137,6 @@ def foo(a: Optional[str]) -> None:
             '3 | def foo(a: Optional[str]) -> None:',
             '4 |     print(a.split(\'.\'))',
             'E | Unexpected error: "split" is not a known member of "None"',
-            *SUMMARY_LINES,
         ],
         consecutive=True,
     )
@@ -165,7 +154,6 @@ def test_unexpected_error_first_line(pytester: Pytester) -> None:
         [
             '1 | from bad_module import foo',
             'E | Unexpected error: Import "bad_module" could not be resolved',
-            *SUMMARY_LINES,
         ],
         consecutive=True,
     )
@@ -193,7 +181,6 @@ def foo(a: Optional[str]) -> None:
             '5 |     if a is not None:',
             '6 |         reveal_type(a)',
             'E | Missing type comment, revealed type: str',
-            *SUMMARY_LINES,
         ],
         consecutive=True,
     )