# Buggy code
def filter_members(
    self, members: List[Tuple[str, Any]], want_all: bool
) -> List[Tuple[str, Any, bool]]:
    """Filter the given member list.

    Members are skipped if

    - they are private (except if given explicitly or the private-members
      option is set)
    - they are special methods (except if given explicitly or the
      special-members option is set)
    - they are undocumented (except if the undoc-members option is set)

    The user can override the skipping decision by connecting to the
    ``autodoc-skip-member`` event.
    """

    def is_filtered_inherited_member(name: str) -> bool:
        if inspect.isclass(self.object):
            for cls in self.object.__mro__:
                if (
                    cls.__name__ == self.options.inherited_members
                    and cls != self.object
                ):
                    # given member is a member of specified *super class*
                    return True
                elif name in cls.__dict__:
                    return False

        return False

    ret = []

    # search for members in source code too
    namespace = ".".join(self.objpath)  # will be empty for modules

    if self.analyzer:
        attr_docs = self.analyzer.find_attr_docs()
    else:
        attr_docs = {}

    # process members and determine which to skip
    for membername, member in members:
        # if isattr is True, the member is documented as an attribute
        if member is INSTANCEATTR:
            isattr = True
        else:
            isattr = False

        doc = getdoc(member, self.get_attr, self.env.config.autodoc_inherit_docstrings)

        # if the member __doc__ is the same as self's __doc__, it's just
        # inherited and therefore not the member's doc
        cls = self.get_attr(member, "__class__", None)
        if cls:
            cls_doc = self.get_attr(cls, "__doc__", None)
            if cls_doc == doc:
                doc = None
        has_doc = bool(doc)

        metadata = extract_metadata(doc)
        if "private" in metadata:
            # consider a member private if docstring has "private" metadata
            isprivate = True
        else:
            isprivate = membername.startswith("_")

        keep = False
        if (
            want_all
            and membername.startswith("__")
            and membername.endswith("__")
            and len(membername) > 4
        ):
            # special __methods__
            if self.options.special_members is ALL:
                if membername == "__doc__":
                    keep = False
                elif is_filtered_inherited_member(membername):
                    keep = False
                else:
                    keep = has_doc or self.options.undoc_members
            elif self.options.special_members:
                if membername in self.options.special_members:
                    keep = has_doc or self.options.undoc_members
        elif (namespace, membername) in attr_docs:
            if want_all and isprivate:
                # ignore members whose name starts with _ by default
                keep = self.options.private_members
            else:
                # keep documented attributes
                keep = True
            isattr = True
        elif want_all and isprivate:
            # ignore members whose name starts with _ by default
            keep = self.options.private_members and (
                has_doc or self.options.undoc_members
            )
        else:
            if self.options.members is ALL and is_filtered_inherited_member(membername):
                keep = False
            else:
                # ignore undocumented members if :undoc-members: is not given
                keep = has_doc or self.options.undoc_members

        # give the user a chance to decide whether this member
        # should be skipped
        if self.env.app:
            # let extensions preprocess docstrings
            try:
                skip_user = self.env.app.emit_firstresult(
                    "autodoc-skip-member",
                    self.objtype,
                    membername,
                    member,
                    not keep,
                    self.options,
                )
                if skip_user is not None:
                    keep = not skip_user
            except Exception as exc:
                logger.warning(
                    __(
                        "autodoc: failed to determine %r to be documented, "
                        "the following exception was raised:\n%s"
                    ),
                    member,
                    exc,
                    type="autodoc",
                )
                keep = False

        if keep:
            ret.append((membername, member, isattr))

    return ret


# Traceback (AttributeError)
# Sphinx version: 3.0.0
# Python version: 3.8.2 (CPython)
# Docutils version: 0.16 release
# Jinja2 version: 2.11.1
# Last messages:
#   reading sources... [ 20%] api/execer
#   reading sources... [ 21%] api/foreign_shells
#   reading sources... [ 22%] api/history/base
#   reading sources... [ 22%] api/history/index
#   reading sources... [ 23%] api/history/json
#   reading sources... [ 24%] api/history/main
#   reading sources... [ 25%] api/history/sqlite
#   reading sources... [ 25%] api/imphooks
#   reading sources... [ 26%] api/index
#   reading sources... [ 27%] api/inspectors
# Loaded extensions:
#   sphinx.ext.mathjax (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/mathjax.py
#   sphinxcontrib.applehelp (1.0.2) from /usr/local/lib/python3.8/site-packages/sphinxcontrib/applehelp/__init__.py
#   sphinxcontrib.devhelp (1.0.2) from /usr/local/lib/python3.8/site-packages/sphinxcontrib/devhelp/__init__.py
#   sphinxcontrib.htmlhelp (1.0.3) from /usr/local/lib/python3.8/site-packages/sphinxcontrib/htmlhelp/__init__.py
#   sphinxcontrib.serializinghtml (1.1.4) from /usr/local/lib/python3.8/site-packages/sphinxcontrib/serializinghtml/__init__.py
#   sphinxcontrib.qthelp (1.0.3) from /usr/local/lib/python3.8/site-packages/sphinxcontrib/qthelp/__init__.py
#   alabaster (0.7.12) from /usr/local/lib/python3.8/site-packages/alabaster/__init__.py
#   sphinx.ext.autodoc.type_comment (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/autodoc/type_comment.py
#   sphinx.ext.autodoc (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/autodoc/__init__.py
#   sphinx.ext.doctest (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/doctest.py
#   sphinx.ext.imgmath (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/imgmath.py
#   sphinx.ext.graphviz (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/graphviz.py
#   sphinx.ext.inheritance_diagram (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/inheritance_diagram.py
#   sphinx.ext.viewcode (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/viewcode.py
#   sphinx.ext.autosummary (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/autosummary/__init__.py
#   numpydoc (0.9.2) from /usr/local/lib/python3.8/site-packages/numpydoc/__init__.py
#   cmdhelp (unknown version) from /xonsh/docs/cmdhelp.py
#   runthis.sphinxext (unknown version) from /usr/local/lib/python3.8/site-packages/runthis/sphinxext.py
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/sphinx/cmd/build.py", line 280, in build_main
app.build(args.force_all, filenames)
File "/usr/local/lib/python3.8/site-packages/sphinx/application.py", line 348, in build
self.builder.build_update()
File "/usr/local/lib/python3.8/site-packages/sphinx/builders/__init__.py", line 297, in build_update
self.build(to_build,
File "/usr/local/lib/python3.8/site-packages/sphinx/builders/__init__.py", line 311, in build
updated_docnames = set(self.read())
File "/usr/local/lib/python3.8/site-packages/sphinx/builders/__init__.py", line 418, in read
self._read_serial(docnames)
File "/usr/local/lib/python3.8/site-packages/sphinx/builders/__init__.py", line 439, in _read_serial
self.read_doc(docname)
File "/usr/local/lib/python3.8/site-packages/sphinx/builders/__init__.py", line 479, in read_doc
doctree = read_doc(self.app, self.env, self.env.doc2path(docname))
File "/usr/local/lib/python3.8/site-packages/sphinx/io.py", line 221, in read_doc
pub.publish()
File "/usr/local/lib/python3.8/site-packages/docutils/core.py", line 217, in publish
self.document = self.reader.read(self.source, self.parser,
File "/usr/local/lib/python3.8/site-packages/sphinx/io.py", line 126, in read
self.parse()
File "/usr/local/lib/python3.8/site-packages/docutils/readers/__init__.py", line 77, in parse
self.parser.parse(self.input, document)
File "/usr/local/lib/python3.8/site-packages/sphinx/parsers.py", line 102, in parse
self.statemachine.run(inputlines, document, inliner=self.inliner)
File "/usr/local/lib/python3.8/site-packages/docutils/parsers/rst/states.py", line 170, in run
results = StateMachineWS.run(self, input_lines, input_offset,
File "/usr/local/lib/python3.8/site-packages/docutils/statemachine.py", line 241, in run
context, next_state, result = self.check_line(
File "/usr/local/lib/python3.8/site-packages/docutils/statemachine.py", line 459, in check_line
return method(match, context, next_state)
File "/usr/local/lib/python3.8/site-packages/docutils/parsers/rst/states.py", line 3005, in text
self.section(title.lstrip(), source, style, lineno + 1, messages)
File "/usr/local/lib/python3.8/site-packages/docutils/parsers/rst/states.py", line 327, in section
self.new_subsection(title, lineno, messages)
File "/usr/local/lib/python3.8/site-packages/docutils/parsers/rst/states.py", line 393, in new_subsection
newabsoffset = self.nested_parse(
File "/usr/local/lib/python3.8/site-packages/docutils/parsers/rst/states.py", line 281, in nested_parse
state_machine.run(block, input_offset, memo=self.memo,
File "/usr/local/lib/python3.8/site-packages/docutils/parsers/rst/states.py", line 196, in run
results = StateMachineWS.run(self, input_lines, input_offset)
File "/usr/local/lib/python3.8/site-packages/docutils/statemachine.py", line 241, in run
context, next_state, result = self.check_line(
File "/usr/local/lib/python3.8/site-packages/docutils/statemachine.py", line 459, in check_line
return method(match, context, next_state)
File "/usr/local/lib/python3.8/site-packages/docutils/parsers/rst/states.py", line 2342, in explicit_markup
nodelist, blank_finish = self.explicit_construct(match)
File "/usr/local/lib/python3.8/site-packages/docutils/parsers/rst/states.py", line 2354, in explicit_construct
return method(self, expmatch)
File "/usr/local/lib/python3.8/site-packages/docutils/parsers/rst/states.py", line 2096, in directive
return self.run_directive(
File "/usr/local/lib/python3.8/site-packages/docutils/parsers/rst/states.py", line 2146, in run_directive
result = directive_instance.run()
File "/usr/local/lib/python3.8/site-packages/sphinx/ext/autodoc/directive.py", line 146, in run
documenter.generate(more_content=self.content)
File "/usr/local/lib/python3.8/site-packages/sphinx/ext/autodoc/__init__.py", line 769, in generate
self.document_members(all_members)
File "/usr/local/lib/python3.8/site-packages/sphinx/ext/autodoc/__init__.py", line 659, in document_members
for (mname, member, isattr) in self.filter_members(members, want_all):
File "/usr/local/lib/python3.8/site-packages/sphinx/ext/autodoc/__init__.py", line 570, in filter_members
metadata = extract_metadata(doc)
File "/usr/local/lib/python3.8/site-packages/sphinx/util/docstrings.py", line 29, in extract_metadata
for line in prepare_docstring(s):
File "/usr/local/lib/python3.8/site-packages/sphinx/util/docstrings.py", line 54, in prepare_docstring
lines = s.expandtabs(tabsize).splitlines()
AttributeError: 'getset_descriptor' object has no attribute 'expandtabs'

# Fixed code
def filter_members(
    self, members: List[Tuple[str, Any]], want_all: bool
) -> List[Tuple[str, Any, bool]]:
    """Filter the given member list.

    Members are skipped if

    - they are private (except if given explicitly or the private-members
      option is set)
    - they are special methods (except if given explicitly or the
      special-members option is set)
    - they are undocumented (except if the undoc-members option is set)

    The user can override the skipping decision by connecting to the
    ``autodoc-skip-member`` event.
    """

    def is_filtered_inherited_member(name: str) -> bool:
        if inspect.isclass(self.object):
            for cls in self.object.__mro__:
                if (
                    cls.__name__ == self.options.inherited_members
                    and cls != self.object
                ):
                    # given member is a member of specified *super class*
                    return True
                elif name in cls.__dict__:
                    return False

        return False

    ret = []

    # search for members in source code too
    namespace = ".".join(self.objpath)  # will be empty for modules

    if self.analyzer:
        attr_docs = self.analyzer.find_attr_docs()
    else:
        attr_docs = {}

    # process members and determine which to skip
    for membername, member in members:
        # if isattr is True, the member is documented as an attribute
        if member is INSTANCEATTR:
            isattr = True
        else:
            isattr = False

        doc = getdoc(member, self.get_attr, self.env.config.autodoc_inherit_docstrings)
        if not isinstance(doc, str):
            # Ignore non-string __doc__
            doc = None

        # if the member __doc__ is the same as self's __doc__, it's just
        # inherited and therefore not the member's doc
        cls = self.get_attr(member, "__class__", None)
        if cls:
            cls_doc = self.get_attr(cls, "__doc__", None)
            if cls_doc == doc:
                doc = None
        has_doc = bool(doc)

        metadata = extract_metadata(doc)
        if "private" in metadata:
            # consider a member private if docstring has "private" metadata
            isprivate = True
        else:
            isprivate = membername.startswith("_")

        keep = False
        if (
            want_all
            and membername.startswith("__")
            and membername.endswith("__")
            and len(membername) > 4
        ):
            # special __methods__
            if self.options.special_members is ALL:
                if membername == "__doc__":
                    keep = False
                elif is_filtered_inherited_member(membername):
                    keep = False
                else:
                    keep = has_doc or self.options.undoc_members
            elif self.options.special_members:
                if membername in self.options.special_members:
                    keep = has_doc or self.options.undoc_members
        elif (namespace, membername) in attr_docs:
            if want_all and isprivate:
                # ignore members whose name starts with _ by default
                keep = self.options.private_members
            else:
                # keep documented attributes
                keep = True
            isattr = True
        elif want_all and isprivate:
            # ignore members whose name starts with _ by default
            keep = self.options.private_members and (
                has_doc or self.options.undoc_members
            )
        else:
            if self.options.members is ALL and is_filtered_inherited_member(membername):
                keep = False
            else:
                # ignore undocumented members if :undoc-members: is not given
                keep = has_doc or self.options.undoc_members

        # give the user a chance to decide whether this member
        # should be skipped
        if self.env.app:
            # let extensions preprocess docstrings
            try:
                skip_user = self.env.app.emit_firstresult(
                    "autodoc-skip-member",
                    self.objtype,
                    membername,
                    member,
                    not keep,
                    self.options,
                )
                if skip_user is not None:
                    keep = not skip_user
            except Exception as exc:
                logger.warning(
                    __(
                        "autodoc: failed to determine %r to be documented, "
                        "the following exception was raised:\n%s"
                    ),
                    member,
                    exc,
                    type="autodoc",
                )
                keep = False

        if keep:
            ret.append((membername, member, isattr))

    return ret