# Buggy code
def isattributedescriptor(obj: Any) -> bool:
    """Check if the object is an attribute like descriptor."""
    if inspect.isdatadescriptor(obj):
        # data descriptor is kind of attribute
        return True
    elif isdescriptor(obj):
        # non data descriptor
        unwrapped = inspect.unwrap(obj)
        if isfunction(unwrapped) or isbuiltin(unwrapped) or inspect.ismethod(unwrapped):
            # attribute must not be either function, builtin and method
            return False
        elif is_cython_function_or_method(unwrapped):
            # attribute must not be either function and method (for cython)
            return False
        elif inspect.isclass(unwrapped):
            # attribute must not be a class
            return False
        elif isinstance(
            unwrapped,
            (ClassMethodDescriptorType, MethodDescriptorType, WrapperDescriptorType),
        ):
            # attribute must not be a method descriptor
            return False
        elif type(unwrapped).__name__ == "instancemethod":
            # attribute must not be an instancemethod (C-API)
            return False
        else:
            return True
    else:
        return False


# Traceback (ValueError)
$ docker run --rm -it python bash
root@da57b757740e:/# git clone https://git.ligo.org/emfollow/gwcelery
Cloning into 'gwcelery'...
warning: redirecting to https://git.ligo.org/emfollow/gwcelery.git/
remote: Enumerating objects: 1558, done.
remote: Counting objects: 100% (1558/1558), done.
remote: Compressing objects: 100% (387/387), done.
remote: Total 13274 (delta 1264), reused 1422 (delta 1163), pack-reused 11716
Receiving objects: 100% (13274/13274), 15.43 MiB | 780.00 KiB/s, done.
Resolving deltas: 100% (9771/9771), done.
root@da57b757740e:/# cd gwcelery
root@da57b757740e:/gwcelery# pip install -r docs-requirements.txt
Collecting celery[redis]==4.4.0
Downloading celery-4.4.0-py2.py3-none-any.whl (421 kB)
|████████████████████████████████| 421 kB 591 kB/s
Collecting matplotlib
Downloading matplotlib-3.2.1-cp38-cp38-manylinux1_x86_64.whl (12.4 MB)
|████████████████████████████████| 12.4 MB 948 kB/s
Collecting seaborn
Downloading seaborn-0.10.0-py3-none-any.whl (215 kB)
|████████████████████████████████| 215 kB 878 kB/s
Collecting sphinx>=1.8.0b1
Downloading Sphinx-3.0.0-py3-none-any.whl (2.8 MB)
|████████████████████████████████| 2.8 MB 1.3 MB/s
Collecting billiard<4.0,>=3.6.1
Downloading billiard-3.6.3.0-py3-none-any.whl (89 kB)
|████████████████████████████████| 89 kB 222 kB/s
Collecting kombu<4.7,>=4.6.7
Downloading kombu-4.6.8-py2.py3-none-any.whl (183 kB)
|████████████████████████████████| 183 kB 576 kB/s
Collecting pytz>dev
Downloading pytz-2019.3-py2.py3-none-any.whl (509 kB)
|████████████████████████████████| 509 kB 1.6 MB/s
Collecting vine==1.3.0
Downloading vine-1.3.0-py2.py3-none-any.whl (14 kB)
Collecting redis>=3.2.0; extra == "redis"
Downloading redis-3.4.1-py2.py3-none-any.whl (71 kB)
|████████████████████████████████| 71 kB 8.1 MB/s
Collecting cycler>=0.10
Downloading cycler-0.10.0-py2.py3-none-any.whl (6.5 kB)
Collecting pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1
Downloading pyparsing-2.4.7-py2.py3-none-any.whl (67 kB)
|████████████████████████████████| 67 kB 7.7 MB/s
Collecting numpy>=1.11
Downloading numpy-1.18.2-cp38-cp38-manylinux1_x86_64.whl (20.6 MB)
|████████████████████████████████| 20.6 MB 245 kB/s
Collecting python-dateutil>=2.1
Downloading python_dateutil-2.8.1-py2.py3-none-any.whl (227 kB)
|████████████████████████████████| 227 kB 578 kB/s
Collecting kiwisolver>=1.0.1
Downloading kiwisolver-1.2.0-cp38-cp38-manylinux1_x86_64.whl (92 kB)
|████████████████████████████████| 92 kB 110 kB/s
Collecting pandas>=0.22.0
Downloading pandas-1.0.3-cp38-cp38-manylinux1_x86_64.whl (10.0 MB)
|████████████████████████████████| 10.0 MB 1.2 MB/s
Collecting scipy>=1.0.1
Downloading scipy-1.4.1-cp38-cp38-manylinux1_x86_64.whl (26.0 MB)
|████████████████████████████████| 26.0 MB 1.6 MB/s
Collecting alabaster<0.8,>=0.7
Downloading alabaster-0.7.12-py2.py3-none-any.whl (14 kB)
Collecting imagesize
Downloading imagesize-1.2.0-py2.py3-none-any.whl (4.8 kB)
Requirement already satisfied: setuptools in /usr/local/lib/python3.8/site-packages (from sphinx>=1.8.0b1->-r docs-requirements.txt (line 4)) (46.1.3)
Collecting docutils>=0.12
Downloading docutils-0.16-py2.py3-none-any.whl (548 kB)
|████████████████████████████████| 548 kB 1.5 MB/s
Collecting requests>=2.5.0
Downloading requests-2.23.0-py2.py3-none-any.whl (58 kB)
|████████████████████████████████| 58 kB 8.7 MB/s
Collecting sphinxcontrib-htmlhelp
Downloading sphinxcontrib_htmlhelp-1.0.3-py2.py3-none-any.whl (96 kB)
|████████████████████████████████| 96 kB 1.3 MB/s
Collecting sphinxcontrib-jsmath
Downloading sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl (5.1 kB)
Collecting sphinxcontrib-serializinghtml
Downloading sphinxcontrib_serializinghtml-1.1.4-py2.py3-none-any.whl (89 kB)
|████████████████████████████████| 89 kB 1.4 MB/s
Collecting sphinxcontrib-qthelp
Downloading sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl (90 kB)
|████████████████████████████████| 90 kB 1.3 MB/s
Collecting sphinxcontrib-applehelp
Downloading sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl (121 kB)
|████████████████████████████████| 121 kB 1.5 MB/s
Collecting babel>=1.3
Downloading Babel-2.8.0-py2.py3-none-any.whl (8.6 MB)
|████████████████████████████████| 8.6 MB 1.8 MB/s
Collecting sphinxcontrib-devhelp
Downloading sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl (84 kB)
|████████████████████████████████| 84 kB 3.8 MB/s
Collecting snowballstemmer>=1.1
Downloading snowballstemmer-2.0.0-py2.py3-none-any.whl (97 kB)
|████████████████████████████████| 97 kB 1.4 MB/s
Collecting packaging
Downloading packaging-20.3-py2.py3-none-any.whl (37 kB)
Collecting Pygments>=2.0
Downloading Pygments-2.6.1-py3-none-any.whl (914 kB)
|████████████████████████████████| 914 kB 489 kB/s
Collecting Jinja2>=2.3
Downloading Jinja2-2.11.1-py2.py3-none-any.whl (126 kB)
|████████████████████████████████| 126 kB 1.2 MB/s
Collecting amqp<2.6,>=2.5.2
Downloading amqp-2.5.2-py2.py3-none-any.whl (49 kB)
|████████████████████████████████| 49 kB 4.6 MB/s
Collecting six
Downloading six-1.14.0-py2.py3-none-any.whl (10 kB)
Collecting chardet<4,>=3.0.2
Downloading chardet-3.0.4-py2.py3-none-any.whl (133 kB)
|████████████████████████████████| 133 kB 1.5 MB/s
Collecting idna<3,>=2.5
Downloading idna-2.9-py2.py3-none-any.whl (58 kB)
|████████████████████████████████| 58 kB 6.9 MB/s
Collecting certifi>=2017.4.17
Downloading certifi-2020.4.5.1-py2.py3-none-any.whl (157 kB)
|████████████████████████████████| 157 kB 762 kB/s
Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1
Downloading urllib3-1.25.8-py2.py3-none-any.whl (125 kB)
|████████████████████████████████| 125 kB 1.5 MB/s
Collecting MarkupSafe>=0.23
Downloading MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl (32 kB)
Installing collected packages: billiard, vine, amqp, kombu, pytz, redis, celery, six, cycler, pyparsing, numpy, python-dateutil, kiwisolver, matplotlib, pandas, scipy, seaborn, alabaster, imagesize, docutils, chardet, idna, certifi, urllib3, requests, sphinxcontrib-htmlhelp, sphinxcontrib-jsmath, sphinxcontrib-serializinghtml, sphinxcontrib-qthelp, sphinxcontrib-applehelp, babel, sphinxcontrib-devhelp, snowballstemmer, packaging, Pygments, MarkupSafe, Jinja2, sphinx
Successfully installed Jinja2-2.11.1 MarkupSafe-1.1.1 Pygments-2.6.1 alabaster-0.7.12 amqp-2.5.2 babel-2.8.0 billiard-3.6.3.0 celery-4.4.0 certifi-2020.4.5.1 chardet-3.0.4 cycler-0.10.0 docutils-0.16 idna-2.9 imagesize-1.2.0 kiwisolver-1.2.0 kombu-4.6.8 matplotlib-3.2.1 numpy-1.18.2 packaging-20.3 pandas-1.0.3 pyparsing-2.4.7 python-dateutil-2.8.1 pytz-2019.3 redis-3.4.1 requests-2.23.0 scipy-1.4.1 seaborn-0.10.0 six-1.14.0 snowballstemmer-2.0.0 sphinx-3.0.0 sphinxcontrib-applehelp-1.0.2 sphinxcontrib-devhelp-1.0.2 sphinxcontrib-htmlhelp-1.0.3 sphinxcontrib-jsmath-1.0.1 sphinxcontrib-qthelp-1.0.3 sphinxcontrib-serializinghtml-1.1.4 urllib3-1.25.8 vine-1.3.0
root@da57b757740e:/gwcelery# python setup.py build_sphinx
running build_sphinx
Running Sphinx v3.0.0
making output directory... done
loading intersphinx inventory from https://docs.python.org/3/objects.inv...
loading intersphinx inventory from https://celery.readthedocs.io/en/latest/objects.inv...
loading intersphinx inventory from https://comet.readthedocs.io/en/stable/objects.inv...
loading intersphinx inventory from https://docs.ligo.org/detchar/data-quality-report/objects.inv...
loading intersphinx inventory from https://htcondor.readthedocs.io/en/stable/objects.inv...
loading intersphinx inventory from https://gwpy.github.io/docs/stable/objects.inv...
loading intersphinx inventory from https://lscsoft.docs.ligo.org/ligo.skymap/objects.inv...
loading intersphinx inventory from https://requests.readthedocs.io/en/master/objects.inv...
loading intersphinx inventory from https://twistedmatrix.com/documents/current/api/objects.inv...
loading intersphinx inventory from https://emfollow.docs.ligo.org/userguide/objects.inv...
building [mo]: targets for 0 po files that are out of date
building [html]: targets for 39 source files that are out of date
updating environment: [new config] 39 added, 0 changed, 0 removed
reading sources... [ 30%] gwcelery.tasks.bayestar
Exception occurred:
File "/usr/local/lib/python3.8/inspect.py", line 524, in unwrap
raise ValueError('wrapper loop when unwrapping {!r}'.format(f))
ValueError: wrapper loop when unwrapping ligo.skymap.io.events
The full traceback has been saved in /tmp/sphinx-err-tpjn3lr4.log, if you want to report the issue to the developers.
Please also report this if it was a user error, so that a better error message can be provided next time.
A bug report can be filed in the tracker at <https://github.com/sphinx-doc/sphinx/issues>. Thanks!
root@da57b757740e:/gwcelery# cat /tmp/sphinx-err-tpjn3lr4.log
# 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... [  7%] contributing
#   reading sources... [ 10%] deployment
#   reading sources... [ 12%] design
#   reading sources... [ 15%] gwcelery
#   reading sources... [ 17%] gwcelery.conf
#   reading sources... [ 20%] gwcelery.email
#   reading sources... [ 23%] gwcelery.lvalert
#   reading sources... [ 25%] gwcelery.sentry
#   reading sources... [ 28%] gwcelery.tasks
#   reading sources... [ 30%] gwcelery.tasks.bayestar
# 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
#   celery.contrib.sphinx (unknown version) from /usr/local/lib/python3.8/site-packages/celery/contrib/sphinx.py
#   matplotlib.sphinxext.plot_directive (3.2.1) from /usr/local/lib/python3.8/site-packages/matplotlib/sphinxext/plot_directive.py
#   sphinx.ext.extlinks (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/extlinks.py
#   sphinx.ext.graphviz (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/graphviz.py
#   sphinx.ext.intersphinx (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/intersphinx.py
#   sphinx.ext.napoleon (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/napoleon/__init__.py
#   sphinx.ext.viewcode (3.0.0) from /usr/local/lib/python3.8/site-packages/sphinx/ext/viewcode.py
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/sphinx/setup_command.py", line 193, in run
app.build(force_all=self.all_files)
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 2769, in underline
self.section(title, 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 660, in document_members
classes = [cls for cls in self.documenters.values()
File "/usr/local/lib/python3.8/site-packages/sphinx/ext/autodoc/__init__.py", line 661, in <listcomp>
if cls.can_document_member(member, mname, isattr, self)]
File "/usr/local/lib/python3.8/site-packages/sphinx/ext/autodoc/__init__.py", line 1553, in can_document_member
if inspect.isattributedescriptor(member):
File "/usr/local/lib/python3.8/site-packages/sphinx/util/inspect.py", line 220, in isattributedescriptor
unwrapped = inspect.unwrap(obj)
File "/usr/local/lib/python3.8/inspect.py", line 524, in unwrap
raise ValueError('wrapper loop when unwrapping {!r}'.format(f))
ValueError: wrapper loop when unwrapping ligo.skymap.io.events

# Fixed code
def isattributedescriptor(obj: Any) -> bool:
    """Check if the object is an attribute like descriptor."""
    if inspect.isdatadescriptor(obj):
        # data descriptor is kind of attribute
        return True
    elif isdescriptor(obj):
        # non data descriptor
        unwrapped = unwrap(obj)
        if isfunction(unwrapped) or isbuiltin(unwrapped) or inspect.ismethod(unwrapped):
            # attribute must not be either function, builtin and method
            return False
        elif is_cython_function_or_method(unwrapped):
            # attribute must not be either function and method (for cython)
            return False
        elif inspect.isclass(unwrapped):
            # attribute must not be a class
            return False
        elif isinstance(
            unwrapped,
            (ClassMethodDescriptorType, MethodDescriptorType, WrapperDescriptorType),
        ):
            # attribute must not be a method descriptor
            return False
        elif type(unwrapped).__name__ == "instancemethod":
            # attribute must not be an instancemethod (C-API)
            return False
        else:
            return True
    else:
        return False