mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #5392 from tk0miya/5290_support_egged_source_code
Fix #5290: autodoc: failed to analyze source code in egg package
This commit is contained in:
commit
0970619813
1
CHANGES
1
CHANGES
@ -40,6 +40,7 @@ Bugs fixed
|
||||
* autodoc: ImportError is replaced by AttributeError for deeper module
|
||||
* #2720, #4034: Incorrect links with ``:download:``, duplicate names, and
|
||||
parallel builds
|
||||
* #5290: autodoc: failed to analyze source code in egg package
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
@ -10,6 +10,9 @@
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import re
|
||||
from zipfile import ZipFile
|
||||
|
||||
from six import iteritems, BytesIO, StringIO
|
||||
|
||||
from sphinx.errors import PycodeError
|
||||
@ -42,9 +45,23 @@ class ModuleAnalyzer(object):
|
||||
obj = cls(f, modname, filename) # type: ignore
|
||||
cls.cache['file', filename] = obj
|
||||
except Exception as err:
|
||||
raise PycodeError('error opening %r' % filename, err)
|
||||
if '.egg/' in filename:
|
||||
obj = cls.cache['file', filename] = cls.for_egg(filename, modname)
|
||||
else:
|
||||
raise PycodeError('error opening %r' % filename, err)
|
||||
return obj
|
||||
|
||||
@classmethod
|
||||
def for_egg(cls, filename, modname):
|
||||
# type: (unicode, unicode) -> ModuleAnalyzer
|
||||
eggpath, relpath = re.split('(?<=\\.egg)/', filename)
|
||||
try:
|
||||
with ZipFile(eggpath) as egg:
|
||||
code = egg.read(relpath).decode('utf-8')
|
||||
return cls.for_string(code, modname, filename)
|
||||
except Exception as exc:
|
||||
raise PycodeError('error opening %r' % filename, exc)
|
||||
|
||||
@classmethod
|
||||
def for_module(cls, modname):
|
||||
# type: (str) -> ModuleAnalyzer
|
||||
|
@ -314,6 +314,11 @@ def get_module_source(modname):
|
||||
filename += 'w'
|
||||
elif not (lfilename.endswith('.py') or lfilename.endswith('.pyw')):
|
||||
raise PycodeError('source is not a .py file: %r' % filename)
|
||||
elif '.egg' in filename:
|
||||
eggpath, _ = re.split('(?<=\\.egg)/', filename)
|
||||
if path.isfile(eggpath):
|
||||
return 'file', filename
|
||||
|
||||
if not path.isfile(filename):
|
||||
raise PycodeError('source file is not present: %r' % filename)
|
||||
return 'file', filename
|
||||
|
8
tests/roots/test-pycode-egg/conf.py
Normal file
8
tests/roots/test-pycode-egg/conf.py
Normal file
@ -0,0 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('sample-0.0.0-py3.7.egg'))
|
||||
master_doc = 'index'
|
||||
extensions = ['sphinx.ext.autodoc']
|
2
tests/roots/test-pycode-egg/index.rst
Normal file
2
tests/roots/test-pycode-egg/index.rst
Normal file
@ -0,0 +1,2 @@
|
||||
test-pycode-egg
|
||||
===============
|
BIN
tests/roots/test-pycode-egg/sample-0.0.0-py3.7.egg
Normal file
BIN
tests/roots/test-pycode-egg/sample-0.0.0-py3.7.egg
Normal file
Binary file not shown.
8
tests/roots/test-pycode-egg/src/sample.py
Normal file
8
tests/roots/test-pycode-egg/src/sample.py
Normal file
@ -0,0 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#: constant on sample.py
|
||||
CONSTANT = 1
|
||||
|
||||
|
||||
def hello(s):
|
||||
print('Hello %s' % s)
|
6
tests/roots/test-pycode-egg/src/setup.py
Normal file
6
tests/roots/test-pycode-egg/src/setup.py
Normal file
@ -0,0 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from setuptools import setup
|
||||
|
||||
|
||||
setup(name='sample',
|
||||
py_modules=['sample'])
|
@ -1584,3 +1584,26 @@ def test_autodoc_default_options_with_values(app):
|
||||
assert ' list of weak references to the object (if defined)' not in actual
|
||||
assert ' .. py:method:: CustomIter.snafucate()' not in actual
|
||||
assert ' Makes this snafucated.' not in actual
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='pycode-egg')
|
||||
def test_autodoc_for_egged_code(app):
|
||||
options = {"members": None,
|
||||
"undoc-members": None}
|
||||
actual = do_autodoc(app, 'module', 'sample', options)
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: sample',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: CONSTANT',
|
||||
' :module: sample',
|
||||
' :annotation: = 1',
|
||||
'',
|
||||
' constant on sample.py',
|
||||
' ',
|
||||
'',
|
||||
'.. py:function:: hello(s)',
|
||||
' :module: sample',
|
||||
''
|
||||
]
|
||||
|
@ -10,6 +10,7 @@
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from six import PY2
|
||||
|
||||
@ -47,6 +48,31 @@ def test_ModuleAnalyzer_for_module():
|
||||
assert analyzer.encoding == 'utf-8'
|
||||
|
||||
|
||||
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'
|
||||
|
Loading…
Reference in New Issue
Block a user