-
Notifications
You must be signed in to change notification settings - Fork 13
Open
Description
Hi,
I found this issue via the test suite, and traced it to the fact that the source files copied by sphinx itself when instantiating the Sphinx object (sphinx_app in sphinxify.py) were read-only. The error looks like:
___________________________ test_sphinxify[outline] ____________________________
build_oinfo = <function fixture_build_oinfo.<locals>._build_oinfo at 0x7fffd551a1f0>
set_docrepr_options = <function fixture_set_docrepr_options.<locals>._set_docrepr_options at 0x7fffd551ae50>
open_browser = <function open_browser.<locals>._open_browser at 0x7fffd54de310>
compare_screenshots = <function compare_screenshots.<locals>._compare_screenshots at 0x7fffd54de4c0>
test_id = 'outline', obj = <ufunc 'sin'>, oinfo_data = {'name': 'sin'}
docrepr_options = {'outline': True}
@pytest.mark.asyncio
@pytest.mark.parametrize(
('test_id', 'obj', 'oinfo_data', 'docrepr_options'),
_test_cases_to_params(TEST_CASES),
ids=list(TEST_CASES.keys()),
)
async def test_sphinxify(
build_oinfo, set_docrepr_options, open_browser, compare_screenshots,
test_id, obj, oinfo_data, docrepr_options,
):
"""Test the operation of the Sphinxify module on various docstrings."""
if (oinfo_data.get('docstring', None) == PLOT_DOCSTRING
and sys.version_info.major == 3
and sys.version_info.minor == 6
and sys.platform.startswith('win')):
pytest.skip(
'Plot fails on Py3.6 on Windows; older version of Matplotlib?')
oinfo = build_oinfo(obj, **oinfo_data)
set_docrepr_options(**docrepr_options)
> url = docrepr.sphinxify.rich_repr(oinfo)
docrepr/tests/test_output.py:240:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/gnu/store/dmcslfpdfyv74mfwwbqliksr255xk8iw-python-docrepr-0.2.0/lib/python3.9/site-packages/docrepr/sphinxify.py:450: in rich_repr
class_doc = sphinxify(wrapped_class_docstring, srcdir)
/gnu/store/dmcslfpdfyv74mfwwbqliksr255xk8iw-python-docrepr-0.2.0/lib/python3.9/site-packages/docrepr/sphinxify.py:405: in sphinxify
merge_directories(destdir, srcdir)
/gnu/store/dmcslfpdfyv74mfwwbqliksr255xk8iw-python-docrepr-0.2.0/lib/python3.9/site-packages/docrepr/utils.py:52: in merge_directories
shutil.copytree(source, destination, dirs_exist_ok=True)
/gnu/store/b6j1qw1a5rkbfvcy7lc9fm95abbzpa4x-python-3.9.9/lib/python3.9/shutil.py:566: in copytree
return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
entries = [<DirEntry 'docstring.html'>, <DirEntry 'search.html'>, <DirEntry '_static'>, <DirEntry '.buildinfo'>, <DirEntry 'searchindex.js'>, <DirEntry 'objects.inv'>]
src = '/tmp/guix-build-python-docrepr-0.2.0.drv-0/tmpev83mper'
dst = '/tmp/guix-build-python-docrepr-0.2.0.drv-0/docrepr-None/tmpbm5c0r1l'
symlinks = False, ignore = None
copy_function = <function copy2 at 0x7ffff73c5d30>
ignore_dangling_symlinks = False, dirs_exist_ok = True
def _copytree(entries, src, dst, symlinks, ignore, copy_function,
ignore_dangling_symlinks, dirs_exist_ok=False):
if ignore is not None:
ignored_names = ignore(os.fspath(src), [x.name for x in entries])
else:
ignored_names = set()
os.makedirs(dst, exist_ok=dirs_exist_ok)
errors = []
use_srcentry = copy_function is copy2 or copy_function is copy
for srcentry in entries:
if srcentry.name in ignored_names:
continue
srcname = os.path.join(src, srcentry.name)
dstname = os.path.join(dst, srcentry.name)
srcobj = srcentry if use_srcentry else srcname
try:
is_symlink = srcentry.is_symlink()
if is_symlink and os.name == 'nt':
# Special check for directory junctions, which appear as
# symlinks but we want to recurse.
lstat = srcentry.stat(follow_symlinks=False)
if lstat.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT:
is_symlink = False
if is_symlink:
linkto = os.readlink(srcname)
if symlinks:
# We can't just leave it to `copy_function` because legacy
# code with a custom `copy_function` may rely on copytree
# doing the right thing.
os.symlink(linkto, dstname)
copystat(srcobj, dstname, follow_symlinks=not symlinks)
else:
# ignore dangling symlink if the flag is on
if not os.path.exists(linkto) and ignore_dangling_symlinks:
continue
# otherwise let the copy occur. copy2 will raise an error
if srcentry.is_dir():
copytree(srcobj, dstname, symlinks, ignore,
copy_function, dirs_exist_ok=dirs_exist_ok)
else:
copy_function(srcobj, dstname)
elif srcentry.is_dir():
copytree(srcobj, dstname, symlinks, ignore, copy_function,
dirs_exist_ok=dirs_exist_ok)
else:
# Will raise a SpecialFileError for unsupported file types
copy_function(srcobj, dstname)
# catch the Error from the recursive copytree so that we can
# continue with other files
except Error as err:
errors.extend(err.args[0])
except OSError as why:
errors.append((srcname, dstname, str(why)))
try:
copystat(src, dst)
except OSError as why:
# Copying file access times may fail on Windows
if getattr(why, 'winerror', None) is None:
errors.append((src, dst, str(why)))
if errors:
> raise Error(errors)
E shutil.Error: [('/tmp/guix-build-python-docrepr-0.2.0.drv-0/tmpev83mper/_static/plot_directive.css', '/tmp/guix-build-python-docrepr-0.2.0.drv-0/docrepr-None/tmpbm5c0r1l/_static/plot_directive.css', "[Errno 13] Permission denied: '/tmp/guix-build-python-docrepr-0.2.0.drv-0/docrepr-None/tmpbm5c0r1l/_static/plot_directive.css'")]
/gnu/store/b6j1qw1a5rkbfvcy7lc9fm95abbzpa4x-python-3.9.9/lib/python3.9/shutil.py:522: Error
I've fixed it by changing except TypeError to except (TypeError, shutil.Error) (which means the copying falls back to the manual routine below the shutil.copytree failed call). A better approach could be to ensure all files are writable after creating the Sphinx object.
Reactions are currently unavailable