summaryrefslogtreecommitdiffstats
path: root/tests/test_pycode.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tests/test_pycode.py200
1 files changed, 200 insertions, 0 deletions
diff --git a/tests/test_pycode.py b/tests/test_pycode.py
new file mode 100644
index 0000000..1f9882e
--- /dev/null
+++ b/tests/test_pycode.py
@@ -0,0 +1,200 @@
+"""Test pycode."""
+
+import os
+import sys
+
+import pytest
+
+import sphinx
+from sphinx.errors import PycodeError
+from sphinx.pycode import ModuleAnalyzer
+
+SPHINX_MODULE_PATH = os.path.splitext(sphinx.__file__)[0] + '.py'
+
+
+def test_ModuleAnalyzer_get_module_source():
+ assert ModuleAnalyzer.get_module_source('sphinx') == (sphinx.__file__, sphinx.__loader__.get_source('sphinx'))
+
+ # failed to obtain source information from builtin modules
+ with pytest.raises(PycodeError):
+ ModuleAnalyzer.get_module_source('builtins')
+ with pytest.raises(PycodeError):
+ ModuleAnalyzer.get_module_source('itertools')
+
+
+def test_ModuleAnalyzer_for_string():
+ analyzer = ModuleAnalyzer.for_string('print("Hello world")', 'module_name')
+ assert analyzer.modname == 'module_name'
+ assert analyzer.srcname == '<string>'
+
+
+def test_ModuleAnalyzer_for_file():
+ analyzer = ModuleAnalyzer.for_string(SPHINX_MODULE_PATH, 'sphinx')
+ assert analyzer.modname == 'sphinx'
+ assert analyzer.srcname == '<string>'
+
+
+def test_ModuleAnalyzer_for_module(rootdir):
+ analyzer = ModuleAnalyzer.for_module('sphinx')
+ assert analyzer.modname == 'sphinx'
+ assert analyzer.srcname in (SPHINX_MODULE_PATH,
+ os.path.abspath(SPHINX_MODULE_PATH))
+
+ path = rootdir / 'test-pycode'
+ sys.path.insert(0, path)
+ try:
+ analyzer = ModuleAnalyzer.for_module('cp_1251_coded')
+ docs = analyzer.find_attr_docs()
+ assert docs == {('', 'X'): ['It MUST look like X="\u0425"', '']}
+ finally:
+ sys.path.pop(0)
+
+
+def test_ModuleAnalyzer_for_file_in_egg(rootdir):
+ try:
+ path = rootdir / 'test-pycode-egg' / 'sample-0.0.0-py3.7.egg'
+ sys.path.insert(0, path)
+
+ import sample
+ analyzer = ModuleAnalyzer.for_file(sample.__file__, 'sample')
+ docs = analyzer.find_attr_docs()
+ assert docs == {('', 'CONSTANT'): ['constant on sample.py', '']}
+ finally:
+ sys.path.pop(0)
+
+
+def test_ModuleAnalyzer_for_module_in_egg(rootdir):
+ try:
+ path = rootdir / 'test-pycode-egg' / 'sample-0.0.0-py3.7.egg'
+ sys.path.insert(0, path)
+
+ analyzer = ModuleAnalyzer.for_module('sample')
+ docs = analyzer.find_attr_docs()
+ assert docs == {('', 'CONSTANT'): ['constant on sample.py', '']}
+ finally:
+ sys.path.pop(0)
+
+
+def test_ModuleAnalyzer_find_tags():
+ code = ('class Foo(object):\n' # line: 1
+ ' """class Foo!"""\n'
+ ' def __init__(self):\n'
+ ' pass\n'
+ '\n'
+ ' def bar(self, arg1, arg2=True, *args, **kwargs):\n'
+ ' """method Foo.bar"""\n'
+ ' pass\n'
+ '\n'
+ ' class Baz(object):\n'
+ ' def __init__(self):\n' # line: 11
+ ' pass\n'
+ '\n'
+ 'def qux():\n'
+ ' """function baz"""\n'
+ ' pass\n'
+ '\n'
+ '@decorator1\n'
+ '@decorator2\n'
+ 'def quux():\n'
+ ' pass\n' # line: 21
+ '\n'
+ 'class Corge(object):\n'
+ ' @decorator1\n'
+ ' @decorator2\n'
+ ' def grault(self):\n'
+ ' pass\n')
+ analyzer = ModuleAnalyzer.for_string(code, 'module')
+ tags = analyzer.find_tags()
+ assert set(tags.keys()) == {'Foo', 'Foo.__init__', 'Foo.bar',
+ 'Foo.Baz', 'Foo.Baz.__init__', 'qux', 'quux',
+ 'Corge', 'Corge.grault'}
+ assert tags['Foo'] == ('class', 1, 12) # type, start, end
+ assert tags['Foo.__init__'] == ('def', 3, 4)
+ assert tags['Foo.bar'] == ('def', 6, 8)
+ assert tags['Foo.Baz'] == ('class', 10, 12)
+ assert tags['Foo.Baz.__init__'] == ('def', 11, 12)
+ assert tags['qux'] == ('def', 14, 16)
+ assert tags['quux'] == ('def', 18, 21)
+ assert tags['Corge'] == ('class', 23, 27)
+ assert tags['Corge.grault'] == ('def', 24, 27)
+
+
+def test_ModuleAnalyzer_find_attr_docs():
+ code = ('class Foo(object):\n'
+ ' """class Foo!"""\n'
+ ' #: comment before attr1\n'
+ ' attr1 = None\n'
+ ' attr2 = None # attribute comment for attr2 (without colon)\n'
+ ' attr3 = None #: attribute comment for attr3\n'
+ ' attr4 = None #: long attribute comment\n'
+ ' #: for attr4\n'
+ ' #: comment before attr5\n'
+ ' attr5 = None #: attribute comment for attr5\n'
+ ' attr6, attr7 = 1, 2 #: this comment is ignored\n'
+ '\n'
+ ' def __init__(self):\n'
+ ' self.attr8 = None #: first attribute comment (ignored)\n'
+ ' self.attr8 = None #: attribute comment for attr8\n'
+ ' #: comment before attr9\n'
+ ' self.attr9 = None #: comment after attr9\n'
+ ' "string after attr9"\n'
+ '\n'
+ ' def bar(self, arg1, arg2=True, *args, **kwargs):\n'
+ ' """method Foo.bar"""\n'
+ ' pass\n'
+ '\n'
+ 'def baz():\n'
+ ' """function baz"""\n'
+ ' pass\n'
+ '\n'
+ 'class Qux: attr1 = 1; attr2 = 2')
+ analyzer = ModuleAnalyzer.for_string(code, 'module')
+ docs = analyzer.find_attr_docs()
+ assert set(docs) == {('Foo', 'attr1'),
+ ('Foo', 'attr3'),
+ ('Foo', 'attr4'),
+ ('Foo', 'attr5'),
+ ('Foo', 'attr6'),
+ ('Foo', 'attr7'),
+ ('Foo', 'attr8'),
+ ('Foo', 'attr9')}
+ assert docs[('Foo', 'attr1')] == ['comment before attr1', '']
+ assert docs[('Foo', 'attr3')] == ['attribute comment for attr3', '']
+ assert docs[('Foo', 'attr4')] == ['long attribute comment', '']
+ assert docs[('Foo', 'attr4')] == ['long attribute comment', '']
+ assert docs[('Foo', 'attr5')] == ['attribute comment for attr5', '']
+ assert docs[('Foo', 'attr6')] == ['this comment is ignored', '']
+ assert docs[('Foo', 'attr7')] == ['this comment is ignored', '']
+ assert docs[('Foo', 'attr8')] == ['attribute comment for attr8', '']
+ assert docs[('Foo', 'attr9')] == ['string after attr9', '']
+ assert analyzer.tagorder == {'Foo': 0,
+ 'Foo.__init__': 8,
+ 'Foo.attr1': 1,
+ 'Foo.attr2': 2,
+ 'Foo.attr3': 3,
+ 'Foo.attr4': 4,
+ 'Foo.attr5': 5,
+ 'Foo.attr6': 6,
+ 'Foo.attr7': 7,
+ 'Foo.attr8': 10,
+ 'Foo.attr9': 12,
+ 'Foo.bar': 13,
+ 'baz': 14,
+ 'Qux': 15,
+ 'Qux.attr1': 16,
+ 'Qux.attr2': 17}
+
+
+@pytest.mark.skipif(sys.version_info < (3, 8),
+ reason='posonlyargs are available since python3.8.')
+def test_ModuleAnalyzer_find_attr_docs_for_posonlyargs_method():
+ code = ('class Foo(object):\n'
+ ' def __init__(self, /):\n'
+ ' self.attr = None #: attribute comment\n')
+ analyzer = ModuleAnalyzer.for_string(code, 'module')
+ docs = analyzer.find_attr_docs()
+ assert set(docs) == {('Foo', 'attr')}
+ assert docs[('Foo', 'attr')] == ['attribute comment', '']
+ assert analyzer.tagorder == {'Foo': 0,
+ 'Foo.__init__': 1,
+ 'Foo.attr': 2}