1"""
2    test_ext_autodoc_autoclass
3    ~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5    Test the autodoc extension.  This tests mainly the Documenters; the auto
6    directives are tested in a test source file translated by test_build.
7
8    :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
9    :license: BSD, see LICENSE for details.
10"""
11
12import sys
13
14import pytest
15
16from .test_ext_autodoc import do_autodoc
17
18
19@pytest.mark.sphinx('html', testroot='ext-autodoc')
20def test_classes(app):
21    actual = do_autodoc(app, 'function', 'target.classes.Foo')
22    assert list(actual) == [
23        '',
24        '.. py:function:: Foo()',
25        '   :module: target.classes',
26        '',
27    ]
28
29    actual = do_autodoc(app, 'function', 'target.classes.Bar')
30    assert list(actual) == [
31        '',
32        '.. py:function:: Bar(x, y)',
33        '   :module: target.classes',
34        '',
35    ]
36
37    actual = do_autodoc(app, 'function', 'target.classes.Baz')
38    assert list(actual) == [
39        '',
40        '.. py:function:: Baz(x, y)',
41        '   :module: target.classes',
42        '',
43    ]
44
45    actual = do_autodoc(app, 'function', 'target.classes.Qux')
46    assert list(actual) == [
47        '',
48        '.. py:function:: Qux(foo, bar)',
49        '   :module: target.classes',
50        '',
51    ]
52
53
54@pytest.mark.sphinx('html', testroot='ext-autodoc')
55def test_instance_variable(app):
56    options = {'members': None}
57    actual = do_autodoc(app, 'class', 'target.instance_variable.Bar', options)
58    assert list(actual) == [
59        '',
60        '.. py:class:: Bar()',
61        '   :module: target.instance_variable',
62        '',
63        '',
64        '   .. py:attribute:: Bar.attr2',
65        '      :module: target.instance_variable',
66        '',
67        '      docstring bar',
68        '',
69        '',
70        '   .. py:attribute:: Bar.attr3',
71        '      :module: target.instance_variable',
72        '',
73        '      docstring bar',
74        '',
75    ]
76
77
78@pytest.mark.sphinx('html', testroot='ext-autodoc')
79def test_inherited_instance_variable(app):
80    options = {'members': None,
81               'inherited-members': None}
82    actual = do_autodoc(app, 'class', 'target.instance_variable.Bar', options)
83    assert list(actual) == [
84        '',
85        '.. py:class:: Bar()',
86        '   :module: target.instance_variable',
87        '',
88        '',
89        '   .. py:attribute:: Bar.attr1',
90        '      :module: target.instance_variable',
91        '',
92        '      docstring foo',
93        '',
94        '',
95        '   .. py:attribute:: Bar.attr2',
96        '      :module: target.instance_variable',
97        '',
98        '      docstring bar',
99        '',
100        '',
101        '   .. py:attribute:: Bar.attr3',
102        '      :module: target.instance_variable',
103        '',
104        '      docstring bar',
105        '',
106    ]
107
108
109@pytest.mark.skipif(sys.version_info < (3, 6), reason='py36+ is available since python3.6.')
110@pytest.mark.sphinx('html', testroot='ext-autodoc')
111def test_uninitialized_attributes(app):
112    options = {"members": None,
113               "inherited-members": None}
114    actual = do_autodoc(app, 'class', 'target.uninitialized_attributes.Derived', options)
115    assert list(actual) == [
116        '',
117        '.. py:class:: Derived()',
118        '   :module: target.uninitialized_attributes',
119        '',
120        '',
121        '   .. py:attribute:: Derived.attr1',
122        '      :module: target.uninitialized_attributes',
123        '      :type: int',
124        '',
125        '      docstring',
126        '',
127        '',
128        '   .. py:attribute:: Derived.attr3',
129        '      :module: target.uninitialized_attributes',
130        '      :type: int',
131        '',
132        '      docstring',
133        '',
134    ]
135
136
137@pytest.mark.skipif(sys.version_info < (3, 6), reason='py36+ is available since python3.6.')
138@pytest.mark.sphinx('html', testroot='ext-autodoc')
139def test_undocumented_uninitialized_attributes(app):
140    options = {"members": None,
141               "inherited-members": None,
142               "undoc-members": None}
143    actual = do_autodoc(app, 'class', 'target.uninitialized_attributes.Derived', options)
144    assert list(actual) == [
145        '',
146        '.. py:class:: Derived()',
147        '   :module: target.uninitialized_attributes',
148        '',
149        '',
150        '   .. py:attribute:: Derived.attr1',
151        '      :module: target.uninitialized_attributes',
152        '      :type: int',
153        '',
154        '      docstring',
155        '',
156        '',
157        '   .. py:attribute:: Derived.attr2',
158        '      :module: target.uninitialized_attributes',
159        '      :type: str',
160        '',
161        '',
162        '   .. py:attribute:: Derived.attr3',
163        '      :module: target.uninitialized_attributes',
164        '      :type: int',
165        '',
166        '      docstring',
167        '',
168        '',
169        '   .. py:attribute:: Derived.attr4',
170        '      :module: target.uninitialized_attributes',
171        '      :type: str',
172        '',
173    ]
174
175
176def test_decorators(app):
177    actual = do_autodoc(app, 'class', 'target.decorator.Baz')
178    assert list(actual) == [
179        '',
180        '.. py:class:: Baz(name=None, age=None)',
181        '   :module: target.decorator',
182        '',
183    ]
184
185    actual = do_autodoc(app, 'class', 'target.decorator.Qux')
186    assert list(actual) == [
187        '',
188        '.. py:class:: Qux(name=None, age=None)',
189        '   :module: target.decorator',
190        '',
191    ]
192
193    actual = do_autodoc(app, 'class', 'target.decorator.Quux')
194    assert list(actual) == [
195        '',
196        '.. py:class:: Quux(name=None, age=None)',
197        '   :module: target.decorator',
198        '',
199    ]
200
201
202@pytest.mark.sphinx('html', testroot='ext-autodoc')
203def test_slots_attribute(app):
204    options = {"members": None}
205    actual = do_autodoc(app, 'class', 'target.slots.Bar', options)
206    assert list(actual) == [
207        '',
208        '.. py:class:: Bar()',
209        '   :module: target.slots',
210        '',
211        '   docstring',
212        '',
213        '',
214        '   .. py:attribute:: Bar.attr1',
215        '      :module: target.slots',
216        '',
217        '      docstring of attr1',
218        '',
219        '',
220        '   .. py:attribute:: Bar.attr2',
221        '      :module: target.slots',
222        '',
223        '      docstring of instance attr2',
224        '',
225    ]
226
227
228@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.')
229@pytest.mark.sphinx('html', testroot='ext-autodoc')
230def test_show_inheritance_for_subclass_of_generic_type(app):
231    options = {'show-inheritance': None}
232    actual = do_autodoc(app, 'class', 'target.classes.Quux', options)
233    assert list(actual) == [
234        '',
235        '.. py:class:: Quux(iterable=(), /)',
236        '   :module: target.classes',
237        '',
238        '   Bases: :class:`List`\\ [:obj:`Union`\\ [:class:`int`, :class:`float`]]',
239        '',
240        '   A subclass of List[Union[int, float]]',
241        '',
242    ]
243
244
245def test_class_alias(app):
246    def autodoc_process_docstring(*args):
247        """A handler always raises an error.
248        This confirms this handler is never called for class aliases.
249        """
250        raise
251
252    app.connect('autodoc-process-docstring', autodoc_process_docstring)
253    actual = do_autodoc(app, 'class', 'target.classes.Alias')
254    assert list(actual) == [
255        '',
256        '.. py:attribute:: Alias',
257        '   :module: target.classes',
258        '',
259        '   alias of :class:`target.classes.Foo`',
260    ]
261