@@ -39,12 +39,80 @@ class Example:
3939 a body giving a longer description of what's going on.
4040 """
4141
42+ my_property_with_only_description = MockProperty ()
43+ """
44+ This is a poorly formatted docstring that does not have
45+ a one-line title. It should result in the property name
46+ being used as a title, and this text as description.
47+ """
48+
49+ # This line looks like an attribute assignment with a docstring,
50+ # but it's not - because we are not assigning to a simple name.
51+ # This tests that such assignments won't cause errors.
52+ my_property_with_nice_docs .attribute = "dummy value"
53+ """A spurious docstring."""
54+
55+ # As above, this is testing that we safely ignore assignments
56+ # that are not to simple names. The code below should not
57+ # cause an error, but will cause a ``continue`` statement
58+ # to skip actions, testing another code path when the
59+ # class is analysed.
60+ dict_attribute = {}
61+ dict_attribute ["foo" ] = "bar"
62+ """Here is a spurious docstring that should be ignored."""
63+
64+ base_descriptor = BaseDescriptor ()
65+ """This descriptor should raise NotImplementedError."""
66+
4267
4368def test_docstrings_are_retrieved ():
44- """Check that the docstring can be picked up from the class definition."""
69+ """Check that the docstring can be picked up from the class definition.
70+
71+ This test checks that:
72+ * We get docstrings for exactly the attributes we expect.
73+ * The one-line docstrings are picked up correctly.
74+ * The docstring-inspection code isn't confused by spurious docstrings
75+ next to assignments that are not to simple names. (see comments on
76+ the class definition of `Example`).
77+
78+ Detection and interpretation of multiline docstrings is tested in
79+ `test_basedescriptor_with_good_docstring`.
80+ """
4581 docs = get_class_attribute_docstrings (Example )
4682 assert docs ["my_constant" ] == "A number that is all mine."
4783 assert docs ["my_property" ] == "Docs for my_property."
84+ expected_names = [
85+ "my_constant" ,
86+ "my_property" ,
87+ "my_property_with_nice_docs" ,
88+ "my_property_with_only_description" ,
89+ "base_descriptor" ,
90+ ]
91+ assert set (docs .keys ()) == set (expected_names )
92+
93+
94+ def test_non_classes_raise_errors ():
95+ """Check we validate the input object.
96+
97+ If `get_class_attribute_docstrings` is called on something other than
98+ a class, we should raise an error.
99+ """
100+
101+ def dummy ():
102+ pass
103+
104+ with pytest .raises (TypeError ):
105+ get_class_attribute_docstrings (dummy )
106+
107+
108+ def test_uncheckable_class ():
109+ """Check we don't crash if we can't check a class.
110+
111+ If `inspect.getsource` fails, we should return an empty dict.
112+ """
113+ MyClass = type ("MyClass" , (), {"intattr" : 10 })
114+ doc = get_class_attribute_docstrings (MyClass )
115+ assert doc == {}
48116
49117
50118def test_docstrings_are_cached ():
@@ -66,6 +134,26 @@ def test_basedescriptor_with_good_docstring():
66134 assert prop .description .startswith ("The docstring" )
67135
68136
137+ def test_basedescriptor_with_oneline_docstring ():
138+ """Check we get the right documentation properties for a one-liner."""
139+ prop = Example .my_property
140+ assert prop .name == "my_property"
141+ assert prop .title == "Docs for my_property."
142+ assert prop .description .startswith ("Docs for my_property." )
143+
144+
145+ def test_basedescriptor_with_bad_multiline_docstring ():
146+ """Check a docstring with no title produces the expected result.
147+
148+ A multiline docstring with no title (i.e. no blank second line)
149+ should result in the whole docstring being used as the description.
150+ """
151+ prop = Example .my_property_with_only_description
152+ assert prop .name == "my_property_with_only_description"
153+ assert prop .title == "This is a poorly formatted docstring that does not have"
154+ assert prop .description .startswith ("This is a poorly formatted" )
155+
156+
69157def test_basedescriptor_orphaned ():
70158 """Check the right error is raised if we ask for the name outside a class."""
71159 prop = MockProperty ()
@@ -92,3 +180,6 @@ def test_basedescriptor_get():
92180 e = Example ()
93181 assert e .my_property == "An example value."
94182 assert isinstance (Example .my_property , MockProperty )
183+ with pytest .raises (NotImplementedError ):
184+ # BaseDescriptor requires `instance_get` to be overridden.
185+ e .base_descriptor
0 commit comments