1
+ from __future__ import annotations
2
+
1
3
import contextlib
2
4
import pathlib
3
5
import re
6
+ import sys
7
+ from collections .abc import Iterator
8
+ from typing import TYPE_CHECKING , Any
4
9
5
- import pytest
6
10
import docutils .core
11
+ import docutils .nodes
12
+ import docutils .utils
13
+ import pytest
7
14
from jaraco .packaging import metadata
8
15
16
+ if TYPE_CHECKING :
17
+ if sys .version_info >= (3 , 12 ):
18
+ from importlib .metadata import PackageMetadata
19
+ else :
20
+ from importlib_metadata import PackageMetadata
21
+
22
+ from _pytest .nodes import Node
23
+ from typing_extensions import Self
9
24
10
25
project_files = 'setup.py' , 'setup.cfg' , 'pyproject.toml'
11
26
12
27
13
- def pytest_collect_file (file_path : pathlib .Path , parent ) :
28
+ def pytest_collect_file (file_path : pathlib .Path , parent : Node ) -> CheckdocsItem | None :
14
29
if file_path .name not in project_files :
15
- return
30
+ return None
16
31
return CheckdocsItem .from_parent (parent , name = 'project' )
17
32
18
33
19
34
class Description (str ):
35
+ content_type : str = ""
36
+
20
37
@classmethod
21
- def from_md (cls , md ) :
38
+ def from_md (cls , md : PackageMetadata ) -> Self :
22
39
desc = cls (md .get ('Description' ))
23
40
desc .content_type = md .get ('Description-Content-Type' , 'text/x-rst' )
24
41
return desc
25
42
26
43
27
44
class CheckdocsItem (pytest .Item ):
28
- def runtest (self ):
45
+ def runtest (self ) -> None :
29
46
desc = self .get_long_description ()
30
47
method_name = f"run_{ re .sub ('[-/]' , '_' , desc .content_type )} "
31
48
getattr (self , method_name )(desc )
32
49
33
- def run_text_markdown (self , desc ) :
50
+ def run_text_markdown (self , desc : str ) -> None :
34
51
"stubbed"
35
52
36
- def run_text_x_rst (self , desc ) :
53
+ def run_text_x_rst (self , desc : str ) -> None :
37
54
with self .monkey_patch_system_message () as reports :
38
55
self .rst2html (desc )
39
56
assert not reports
40
57
41
58
@contextlib .contextmanager
42
- def monkey_patch_system_message (self ):
43
- reports = []
59
+ def monkey_patch_system_message (self ) -> Iterator [ list [ str | Exception ]] :
60
+ reports : list [ str | Exception ] = []
44
61
orig = docutils .utils .Reporter .system_message
45
62
46
- def system_message (reporter , level , message , * children , ** kwargs ):
63
+ def system_message (
64
+ reporter : docutils .utils .Reporter ,
65
+ level : int ,
66
+ message : str | Exception ,
67
+ * children : docutils .nodes .Node ,
68
+ ** kwargs : Any ,
69
+ ) -> docutils .nodes .system_message :
47
70
result = orig (reporter , level , message , * children , ** kwargs )
48
71
if level >= reporter .WARNING_LEVEL :
49
72
# All reST failures preventing doc publishing go to reports
@@ -52,17 +75,14 @@ def system_message(reporter, level, message, *children, **kwargs):
52
75
53
76
return result
54
77
55
- docutils .utils .Reporter .system_message = system_message
78
+ docutils .utils .Reporter .system_message = system_message # type: ignore[assignment] # type-stubs expands the kwargs
56
79
yield reports
57
- docutils .utils .Reporter .system_message = orig
80
+ docutils .utils .Reporter .system_message = orig # type: ignore[method-assign]
58
81
59
- def get_long_description (self ):
82
+ def get_long_description (self ) -> Description :
60
83
return Description .from_md (metadata .load ('.' ))
61
84
62
85
@staticmethod
63
- def rst2html (value ):
64
- docutils_settings = {}
65
- parts = docutils .core .publish_parts (
66
- source = value , writer_name = "html4css1" , settings_overrides = docutils_settings
67
- )
68
- return parts ['whole' ]
86
+ def rst2html (value : str ) -> str :
87
+ parts = docutils .core .publish_parts (source = value , writer_name = "html4css1" )
88
+ return parts ['whole' ] # type: ignore[no-any-return] # python/typeshed#12595
0 commit comments