@@ -219,6 +219,9 @@ def test_property_set_name_incorrect_args(self):
219
219
class PropertySub (property ):
220
220
"""This is a subclass of property"""
221
221
222
+ class PropertySubWoDoc (property ):
223
+ pass
224
+
222
225
class PropertySubSlots (property ):
223
226
"""This is a subclass of property that defines __slots__"""
224
227
__slots__ = ()
@@ -237,6 +240,38 @@ def spam(self):
237
240
else :
238
241
raise Exception ("AttributeError not raised" )
239
242
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
+
240
275
@unittest .skipIf (sys .flags .optimize >= 2 ,
241
276
"Docstrings are omitted with -O2 and above" )
242
277
def test_docstring_copy (self ):
@@ -249,6 +284,66 @@ def spam(self):
249
284
Foo .spam .__doc__ ,
250
285
"spam wrapped in property subclass" )
251
286
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
+
252
347
@unittest .skipIf (sys .flags .optimize >= 2 ,
253
348
"Docstrings are omitted with -O2 and above" )
254
349
def test_property_setter_copies_getter_docstring (self ):
0 commit comments