autodoc: Handle explicit instance attributes in :members: (re #904)

This commit is contained in:
Jonathan Waltman 2012-11-08 21:19:47 -06:00
parent 34cbd684a9
commit 6f9e541ab5
3 changed files with 75 additions and 14 deletions

View File

@ -489,20 +489,26 @@ class Documenter(object):
If *want_all* is True, return all members. Else, only return those
members given by *self.options.members* (which may also be none).
"""
analyzed_member_names = set()
if self.analyzer:
attr_docs = self.analyzer.find_attr_docs()
namespace = '.'.join(self.objpath)
for item in attr_docs.iteritems():
if item[0][0] == namespace:
analyzed_member_names.add(item[0][1])
if not want_all:
if not self.options.members:
return False, []
# specific members given
ret = []
members = []
for mname in self.options.members:
try:
ret.append((mname, self.get_attr(self.object, mname)))
members.append((mname, self.get_attr(self.object, mname)))
except AttributeError:
if mname not in analyzed_member_names:
self.directive.warn('missing attribute %s in object %s'
% (mname, self.fullname))
return False, ret
if self.options.inherited_members:
elif self.options.inherited_members:
# safe_getmembers() uses dir() which pulls in members from all
# base classes
members = safe_getmembers(self.object)
@ -521,13 +527,10 @@ class Documenter(object):
for mname in obj_dict.keys()]
membernames = set(m[0] for m in members)
# add instance attributes from the analyzer
if self.analyzer:
attr_docs = self.analyzer.find_attr_docs()
namespace = '.'.join(self.objpath)
for item in attr_docs.iteritems():
if item[0][0] == namespace:
if item[0][1] not in membernames:
members.append((item[0][1], INSTANCEATTR))
for aname in analyzed_member_names:
if aname not in membernames and \
(want_all or aname in self.options.members):
members.append((aname, INSTANCEATTR))
return False, sorted(members)
def filter_members(self, members, want_all):

View File

@ -32,3 +32,16 @@ Just testing a few autodoc possibilities...
:noindex:
.. autoclass:: MarkupError
.. currentmodule:: test_autodoc
.. autoclass:: InstAttCls
:members:
All members (5 total)
.. autoclass:: InstAttCls
:members: ca1, ia1
Specific members (2 total)

View File

@ -540,6 +540,32 @@ def test_generate():
assert_result_contains(
' :annotation: = None', 'attribute', 'AttCls.a2')
# test explicit members with instance attributes
del directive.env.temp_data['autodoc:class']
del directive.env.temp_data['autodoc:module']
directive.env.temp_data['py:module'] = 'test_autodoc'
options.inherited_members = False
options.undoc_members = False
options.members = ALL
assert_processes([
('class', 'test_autodoc.InstAttCls'),
('attribute', 'test_autodoc.InstAttCls.ca1'),
('attribute', 'test_autodoc.InstAttCls.ca2'),
('attribute', 'test_autodoc.InstAttCls.ca3'),
('attribute', 'test_autodoc.InstAttCls.ia1'),
('attribute', 'test_autodoc.InstAttCls.ia2'),
], 'class', 'InstAttCls')
del directive.env.temp_data['autodoc:class']
del directive.env.temp_data['autodoc:module']
options.members = ['ca1', 'ia1']
assert_processes([
('class', 'test_autodoc.InstAttCls'),
('attribute', 'test_autodoc.InstAttCls.ca1'),
('attribute', 'test_autodoc.InstAttCls.ia1'),
], 'class', 'InstAttCls')
del directive.env.temp_data['autodoc:class']
del directive.env.temp_data['autodoc:module']
del directive.env.temp_data['py:module']
# --- generate fodder ------------
@ -680,3 +706,22 @@ class StrRepr(str):
class AttCls(object):
a1 = StrRepr('hello\nworld')
a2 = None
class InstAttCls(object):
"""Class with documented class and instance attributes."""
#: Doc comment for class attribute InstAttCls.ca1.
#: It can have multiple lines.
ca1 = 'a'
ca2 = 'b' #: Doc comment for InstAttCls.ca2. One line only.
ca3 = 'c'
"""Docstring for class attribute InstAttCls.ca3."""
def __init__(self):
#: Doc comment for instance attribute InstAttCls.ia1
self.ia1 = 'd'
self.ia2 = 'e'
"""Docstring for instance attribute InstAttCls.ia2."""