23
23
import inspect
24
24
import importlib
25
25
import doctest
26
- import textwrap
26
+ import pydoc
27
27
try :
28
28
from io import StringIO
29
29
except ImportError :
39
39
from numpydoc .docscrape import NumpyDocString
40
40
41
41
42
+ PRIVATE_CLASSES = ['NDFrame' , 'IndexOpsMixin' ]
43
+
44
+
42
45
def _to_original_callable (obj ):
43
46
while True :
44
47
if inspect .isfunction (obj ) or inspect .isclass (obj ):
@@ -72,8 +75,7 @@ class Docstring:
72
75
def __init__ (self , method_name , method_obj ):
73
76
self .method_name = method_name
74
77
self .method_obj = method_obj
75
- self .raw_doc = method_obj .__doc__ or ''
76
- self .raw_doc = textwrap .dedent (self .raw_doc )
78
+ self .raw_doc = pydoc .getdoc (method_obj )
77
79
self .doc = NumpyDocString (self .raw_doc )
78
80
79
81
def __len__ (self ):
@@ -127,7 +129,12 @@ def doc_parameters(self):
127
129
128
130
@property
129
131
def signature_parameters (self ):
130
- if not inspect .isfunction (self .method_obj ):
132
+ if not (inspect .isfunction (self .method_obj )
133
+ or inspect .isclass (self .method_obj )):
134
+ return tuple ()
135
+ if (inspect .isclass (self .method_obj )
136
+ and self .method_name .split ('.' )[- 1 ] in {'dt' , 'str' , 'cat' }):
137
+ # accessor classes have a signature, but don't want to show this
131
138
return tuple ()
132
139
params = tuple (inspect .signature (self .method_obj ).parameters .keys ())
133
140
if params and params [0 ] in ('self' , 'cls' ):
@@ -149,7 +156,8 @@ def parameter_mismatches(self):
149
156
extra = set (doc_params ) - set (signature_params )
150
157
if extra :
151
158
errs .append ('Unknown parameters {!r}' .format (extra ))
152
- if not missing and not extra and signature_params != doc_params :
159
+ if (not missing and not extra and signature_params != doc_params
160
+ and not (not signature_params and not doc_params )):
153
161
errs .append ('Wrong parameters order. ' +
154
162
'Actual: {!r}. ' .format (signature_params ) +
155
163
'Documented: {!r}' .format (doc_params ))
@@ -180,6 +188,10 @@ def deprecated(self):
180
188
bool (pattern .search (self .summary )) or
181
189
bool (pattern .search (self .extended_summary )))
182
190
191
+ @property
192
+ def mentioned_private_classes (self ):
193
+ return [klass for klass in PRIVATE_CLASSES if klass in self .raw_doc ]
194
+
183
195
@property
184
196
def examples_errors (self ):
185
197
flags = doctest .NORMALIZE_WHITESPACE | doctest .IGNORE_EXCEPTION_DETAIL
@@ -311,6 +323,11 @@ def validate_one(func_name):
311
323
for param_err in param_errs :
312
324
errs .append ('\t {}' .format (param_err ))
313
325
326
+ mentioned_errs = doc .mentioned_private_classes
327
+ if mentioned_errs :
328
+ errs .append ('Private classes ({}) should not be mentioned in public '
329
+ 'docstring.' .format (mentioned_errs ))
330
+
314
331
examples_errs = ''
315
332
if not doc .examples :
316
333
errs .append ('No examples section found' )
0 commit comments