@@ -52,6 +52,9 @@ def test_sections_without_signature():
5252 nada: SEGFAULT.
5353 rien: SEGFAULT.
5454
55+ Keyword Args:
56+ keywd: SEGFAULT.
57+
5558 Exceptions:
5659 GlobalError: when nothing works as expected.
5760
@@ -60,8 +63,8 @@ def test_sections_without_signature():
6063 """
6164 )
6265
63- assert len (sections ) == 4
64- assert len (errors ) == 5 # missing annotations for params and return
66+ assert len (sections ) == 5
67+ assert len (errors ) == 6 # missing annotations for params and return
6568 for error in errors [:- 1 ]:
6669 assert "param" in error
6770 assert "return" in errors [- 1 ]
@@ -79,43 +82,49 @@ def test_property_docstring():
7982def test_function_without_annotations ():
8083 """Parse a function docstring without signature annotations."""
8184
82- def f (x , y ):
85+ def f (x , y , * , z ):
8386 """
8487 This function has no annotations.
8588
8689 Parameters:
8790 x: X value.
8891 y: Y value.
8992
93+ Keyword Args:
94+ z: Z value.
95+
9096 Returns:
91- Sum X + Y.
97+ Sum X + Y + Z .
9298 """
93- return x + y
99+ return x + y + z
94100
95101 sections , errors = parse (inspect .getdoc (f ), inspect .signature (f ))
96- assert len (sections ) == 3
102+ assert len (sections ) == 4
97103 assert len (errors ) == 1
98104 assert "No type in return" in errors [0 ]
99105
100106
101107def test_function_with_annotations ():
102108 """Parse a function docstring with signature annotations."""
103109
104- def f (x : int , y : int ) -> int :
110+ def f (x : int , y : int , * , z : int ) -> int :
105111 """
106112 This function has annotations.
107113
108114 Parameters:
109115 x: X value.
110116 y: Y value.
111117
118+ Keyword Arguments:
119+ z: Z value.
120+
112121 Returns:
113122 Sum X + Y.
114123 """
115124 return x + y
116125
117126 sections , errors = parse (inspect .getdoc (f ), inspect .signature (f ))
118- assert len (sections ) == 3
127+ assert len (sections ) == 4
119128 assert not errors
120129
121130
@@ -188,25 +197,34 @@ def f(x: int, y: int) -> int:
188197def test_types_in_docstring ():
189198 """Parse types in docstring."""
190199
191- def f (x , y ):
200+ def f (x , y , * , z ):
192201 """
193202 The types are written in the docstring.
194203
195204 Parameters:
196205 x (int): X value.
197206 y (int): Y value.
198207
208+ Keyword Args:
209+ z (int): Z value.
210+
199211 Returns:
200- int: Sum X + Y.
212+ int: Sum X + Y + Z .
201213 """
202- return x + y
214+ return x + y + z
203215
204216 sections , errors = parse (inspect .getdoc (f ), inspect .signature (f ))
205- assert len (sections ) == 3
217+ assert len (sections ) == 4
206218 assert not errors
207219
220+ assert sections [0 ].type == Section .Type .MARKDOWN
221+ assert sections [1 ].type == Section .Type .PARAMETERS
222+ assert sections [2 ].type == Section .Type .KEYWORD_ARGS
223+ assert sections [3 ].type == Section .Type .RETURN
224+
208225 x , y = sections [1 ].value
209- r = sections [2 ].value
226+ (z ,) = sections [2 ].value
227+ r = sections [3 ].value
210228
211229 assert x .name == "x"
212230 assert x .annotation == "int"
@@ -220,31 +238,45 @@ def f(x, y):
220238 assert y .kind is inspect .Parameter .POSITIONAL_OR_KEYWORD
221239 assert y .default is inspect .Signature .empty
222240
241+ assert z .name == "z"
242+ assert z .annotation == "int"
243+ assert z .description == "Z value."
244+ assert z .kind is inspect .Parameter .KEYWORD_ONLY
245+ assert z .default is inspect .Signature .empty
246+
223247 assert r .annotation == "int"
224- assert r .description == "Sum X + Y."
248+ assert r .description == "Sum X + Y + Z ."
225249
226250
227251def test_types_and_optional_in_docstring ():
228252 """Parse optional types in docstring."""
229253
230- def f (x = 1 , y = None ):
254+ def f (x = 1 , y = None , * , z = None ):
231255 """
232256 The types are written in the docstring.
233257
234258 Parameters:
235259 x (int): X value.
236260 y (int, optional): Y value.
237261
262+ Keyword Args:
263+ z (int, optional): Z value.
264+
238265 Returns:
239- int: Sum X + Y.
266+ int: Sum X + Y + Z .
240267 """
241- return x + (y or 1 )
268+ return x + (y or 1 ) + ( z or 1 )
242269
243270 sections , errors = parse (inspect .getdoc (f ), inspect .signature (f ))
244- assert len (sections ) == 3
271+ assert len (sections ) == 4
245272 assert not errors
246273
274+ assert sections [0 ].type == Section .Type .MARKDOWN
275+ assert sections [1 ].type == Section .Type .PARAMETERS
276+ assert sections [2 ].type == Section .Type .KEYWORD_ARGS
277+
247278 x , y = sections [1 ].value
279+ (z ,) = sections [2 ].value
248280
249281 assert x .name == "x"
250282 assert x .annotation == "int"
@@ -258,25 +290,34 @@ def f(x=1, y=None):
258290 assert y .kind is inspect .Parameter .POSITIONAL_OR_KEYWORD
259291 assert y .default is None
260292
293+ assert z .name == "z"
294+ assert z .annotation == "int"
295+ assert z .description == "Z value."
296+ assert z .kind is inspect .Parameter .KEYWORD_ONLY
297+ assert z .default is None
298+
261299
262300def test_types_in_signature_and_docstring ():
263301 """Parse types in both signature and docstring."""
264302
265- def f (x : int , y : int ) -> int :
303+ def f (x : int , y : int , * , z : int ) -> int :
266304 """
267305 The types are written both in the signature and in the docstring.
268306
269307 Parameters:
270308 x (int): X value.
271309 y (int): Y value.
272310
311+ Keyword Args:
312+ z (int): Z value.
313+
273314 Returns:
274- int: Sum X + Y.
315+ int: Sum X + Y + Z .
275316 """
276- return x + y
317+ return x + y + z
277318
278319 sections , errors = parse (inspect .getdoc (f ), inspect .signature (f ))
279- assert len (sections ) == 3
320+ assert len (sections ) == 4
280321 assert not errors
281322
282323
@@ -401,6 +442,23 @@ def f(x: int):
401442 assert "Empty" in errors [1 ]
402443
403444
445+ def test_param_line_without_colon_keyword_only ():
446+ """Warn when missing colon."""
447+
448+ def f (* , x : int ):
449+ """
450+ Keyword Args:
451+ x is an integer.
452+ """
453+ return x
454+
455+ sections , errors = parse (inspect .getdoc (f ), inspect .signature (f ))
456+ assert not sections # getting x fails, so the section is empty and discarded
457+ assert len (errors ) == 2
458+ assert "pair" in errors [0 ]
459+ assert "Empty" in errors [1 ]
460+
461+
404462def test_admonitions ():
405463 """Parse admonitions."""
406464
@@ -493,6 +551,35 @@ def f(a, *args, **kwargs):
493551 assert not errors
494552
495553
554+ def test_parse_args_kwargs_keyword_only ():
555+ """Parse args and kwargs."""
556+
557+ def f (a , * args , ** kwargs ):
558+ """
559+ Arguments:
560+ a: a parameter.
561+ *args: args parameters.
562+
563+ Keyword Args:
564+ **kwargs: kwargs parameters.
565+ """
566+ return 1
567+
568+ sections , errors = parse (inspect .getdoc (f ), inspect .signature (f ))
569+ assert len (sections ) == 2
570+ expected_parameters = {"a" : "a parameter." , "*args" : "args parameters." }
571+ for param in sections [0 ].value :
572+ assert param .name in expected_parameters
573+ assert expected_parameters [param .name ] == param .description
574+
575+ expected_parameters = {"**kwargs" : "kwargs parameters." }
576+ for param in sections [1 ].value :
577+ assert param .name in expected_parameters
578+ assert expected_parameters [param .name ] == param .description
579+
580+ assert not errors
581+
582+
496583def test_different_indentation ():
497584 """Parse different indentations, warn on confusing indentation."""
498585
0 commit comments