@@ -219,6 +219,9 @@ def test_property_set_name_incorrect_args(self):
219219class PropertySub (property ):
220220 """This is a subclass of property"""
221221
222+ class PropertySubWoDoc (property ):
223+ pass
224+
222225class PropertySubSlots (property ):
223226 """This is a subclass of property that defines __slots__"""
224227 __slots__ = ()
@@ -237,6 +240,38 @@ def spam(self):
237240 else :
238241 raise Exception ("AttributeError not raised" )
239242
243+ @unittest .skipIf (sys .flags .optimize >= 2 ,
244+ "Docstrings are omitted with -O2 and above" )
245+ def test_issue41287 (self ):
246+
247+ self .assertEqual (PropertySub .__doc__ , "This is a subclass of property" ,
248+ "Docstring of `property` subclass is ignored" )
249+
250+ doc = PropertySub (None , None , None , "issue 41287 is fixed" ).__doc__
251+ self .assertEqual (doc , "issue 41287 is fixed" ,
252+ "Subclasses of `property` ignores `doc` constructor argument" )
253+
254+ def getter (x ):
255+ """Getter docstring"""
256+
257+ def getter_wo_doc (x ):
258+ pass
259+
260+ for ps in property , PropertySub , PropertySubWoDoc :
261+ doc = ps (getter , None , None , "issue 41287 is fixed" ).__doc__
262+ self .assertEqual (doc , "issue 41287 is fixed" ,
263+ "Getter overrides explicit property docstring (%s)" % ps .__name__ )
264+
265+ doc = ps (getter , None , None , None ).__doc__
266+ self .assertEqual (doc , "Getter docstring" , "Getter docstring is not picked-up (%s)" % ps .__name__ )
267+
268+ doc = ps (getter_wo_doc , None , None , "issue 41287 is fixed" ).__doc__
269+ self .assertEqual (doc , "issue 41287 is fixed" ,
270+ "Getter overrides explicit property docstring (%s)" % ps .__name__ )
271+
272+ doc = ps (getter_wo_doc , None , None , None ).__doc__
273+ self .assertIsNone (doc , "Property class doc appears in instance __doc__ (%s)" % ps .__name__ )
274+
240275 @unittest .skipIf (sys .flags .optimize >= 2 ,
241276 "Docstrings are omitted with -O2 and above" )
242277 def test_docstring_copy (self ):
@@ -249,6 +284,66 @@ def spam(self):
249284 Foo .spam .__doc__ ,
250285 "spam wrapped in property subclass" )
251286
287+ @unittest .skipIf (sys .flags .optimize >= 2 ,
288+ "Docstrings are omitted with -O2 and above" )
289+ def test_docstring_copy2 (self ):
290+ """
291+ Property tries to provide the best docstring it finds for its instances.
292+ If a user-provided docstring is available, it is preserved on copies.
293+ If no docstring is available during property creation, the property
294+ will utilize the docstring from the getter if available.
295+ """
296+ def getter1 (self ):
297+ return 1
298+ def getter2 (self ):
299+ """doc 2"""
300+ return 2
301+ def getter3 (self ):
302+ """doc 3"""
303+ return 3
304+
305+ # Case-1: user-provided doc is preserved in copies
306+ # of property with undocumented getter
307+ p = property (getter1 , None , None , "doc-A" )
308+
309+ p2 = p .getter (getter2 )
310+ self .assertEqual (p .__doc__ , "doc-A" )
311+ self .assertEqual (p2 .__doc__ , "doc-A" )
312+
313+ # Case-2: user-provided doc is preserved in copies
314+ # of property with documented getter
315+ p = property (getter2 , None , None , "doc-A" )
316+
317+ p2 = p .getter (getter3 )
318+ self .assertEqual (p .__doc__ , "doc-A" )
319+ self .assertEqual (p2 .__doc__ , "doc-A" )
320+
321+ # Case-3: with no user-provided doc new getter doc
322+ # takes precendence
323+ p = property (getter2 , None , None , None )
324+
325+ p2 = p .getter (getter3 )
326+ self .assertEqual (p .__doc__ , "doc 2" )
327+ self .assertEqual (p2 .__doc__ , "doc 3" )
328+
329+ # Case-4: A user-provided doc is assigned after property construction
330+ # with documented getter. The doc IS NOT preserved.
331+ # It's an odd behaviour, but it's a strange enough
332+ # use case with no easy solution.
333+ p = property (getter2 , None , None , None )
334+ p .__doc__ = "user"
335+ p2 = p .getter (getter3 )
336+ self .assertEqual (p .__doc__ , "user" )
337+ self .assertEqual (p2 .__doc__ , "doc 3" )
338+
339+ # Case-5: A user-provided doc is assigned after property construction
340+ # with UNdocumented getter. The doc IS preserved.
341+ p = property (getter1 , None , None , None )
342+ p .__doc__ = "user"
343+ p2 = p .getter (getter2 )
344+ self .assertEqual (p .__doc__ , "user" )
345+ self .assertEqual (p2 .__doc__ , "user" )
346+
252347 @unittest .skipIf (sys .flags .optimize >= 2 ,
253348 "Docstrings are omitted with -O2 and above" )
254349 def test_property_setter_copies_getter_docstring (self ):
0 commit comments