1
1
import pytest
2
+ import sys
2
3
import warnings
4
+ from inspect import getsourcelines
3
5
4
6
from numpydoc import validate
5
7
import numpydoc .tests
@@ -1528,6 +1530,35 @@ def test_bad_docstrings(self, capsys, klass, func, msgs):
1528
1530
assert msg in " " .join (err [1 ] for err in result ["errors" ])
1529
1531
1530
1532
1533
+ def decorator (x ):
1534
+ """Test decorator."""
1535
+ return x
1536
+
1537
+
1538
+ @decorator
1539
+ @decorator
1540
+ class DecoratorClass :
1541
+ """
1542
+ Class and methods with decorators.
1543
+
1544
+ `DecoratorClass` has two decorators, `DecoratorClass.test_no_decorator` has no
1545
+ decorator and `DecoratorClass.test_three_decorators` has three decorators.
1546
+ `Validator.source_file_def_line` should return the `def` or `class` line number, not
1547
+ the line of the first decorator.
1548
+ """
1549
+
1550
+ def test_no_decorator (self ):
1551
+ """Test method without decorators."""
1552
+ pass
1553
+
1554
+ @decorator
1555
+ @decorator
1556
+ @decorator
1557
+ def test_three_decorators (self ):
1558
+ """Test method with three decorators."""
1559
+ pass
1560
+
1561
+
1531
1562
class TestValidatorClass :
1532
1563
@pytest .mark .parametrize ("invalid_name" , ["unknown_mod" , "unknown_mod.MyClass" ])
1533
1564
def test_raises_for_invalid_module_name (self , invalid_name ):
@@ -1544,3 +1575,31 @@ def test_raises_for_invalid_attribute_name(self, invalid_name):
1544
1575
msg = f"'{ obj_name } ' has no attribute '{ invalid_attr_name } '"
1545
1576
with pytest .raises (AttributeError , match = msg ):
1546
1577
numpydoc .validate .Validator ._load_obj (invalid_name )
1578
+
1579
+ # inspect.getsourcelines does not return class decorators for Python 3.8. This was
1580
+ # fixed starting with 3.9: https://github.com/python/cpython/issues/60060
1581
+ @pytest .mark .parametrize (
1582
+ ["decorated_obj" , "def_line" ],
1583
+ [
1584
+ [
1585
+ "numpydoc.tests.test_validate.DecoratorClass" ,
1586
+ getsourcelines (DecoratorClass )[- 1 ]
1587
+ + (2 if sys .version_info .minor > 8 else 0 ),
1588
+ ],
1589
+ [
1590
+ "numpydoc.tests.test_validate.DecoratorClass.test_no_decorator" ,
1591
+ getsourcelines (DecoratorClass .test_no_decorator )[- 1 ],
1592
+ ],
1593
+ [
1594
+ "numpydoc.tests.test_validate.DecoratorClass.test_three_decorators" ,
1595
+ getsourcelines (DecoratorClass .test_three_decorators )[- 1 ] + 3 ,
1596
+ ],
1597
+ ],
1598
+ )
1599
+ def test_source_file_def_line_with_decorators (self , decorated_obj , def_line ):
1600
+ doc = numpydoc .validate .Validator (
1601
+ numpydoc .docscrape .get_doc_object (
1602
+ numpydoc .validate .Validator ._load_obj (decorated_obj )
1603
+ )
1604
+ )
1605
+ assert doc .source_file_def_line == def_line
0 commit comments