Skip to content
This repository was archived by the owner on Jan 13, 2024. It is now read-only.

Commit 7f59a3b

Browse files
sdpythonxadupre
andauthored
Fixes attribute source missing for sphinx>6 (#383)
* Fixes attribute source missing for sphinx>6 * fix epkg and bloglist * fix unit test Co-authored-by: xadupre <xadupre@microsoft.com>
1 parent b23d4d1 commit 7f59a3b

File tree

7 files changed

+78
-65
lines changed

7 files changed

+78
-65
lines changed

_unittests/ut_helpgen/test_rst2html_toc.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
import unittest
99

1010
from pyquickhelper.loghelper.flog import fLOG
11-
from pyquickhelper.pycode import get_temp_folder, is_travis_or_appveyor
11+
from pyquickhelper.pycode import (
12+
get_temp_folder, is_travis_or_appveyor, ignore_warnings)
1213
from pyquickhelper.helpgen import rst2html
1314

1415

1516
class TestRst2HtmlToc(unittest.TestCase):
1617

18+
@ignore_warnings(PendingDeprecationWarning)
1719
def test_rst2html_toc(self):
1820
fLOG(
1921
__file__,
@@ -58,6 +60,7 @@ def test_rst2html_toc(self):
5860
f.write(text)
5961
self.assertIn("* :ref:`title2`", text)
6062

63+
@ignore_warnings(PendingDeprecationWarning)
6164
def test_rst2html_autoclass(self):
6265
fLOG(
6366
__file__,
@@ -89,6 +92,7 @@ def test_rst2html_autoclass(self):
8992
f.write(text)
9093
self.assertIn("* ``:indent:<int>`` to indent the output", text)
9194

95+
@ignore_warnings(PendingDeprecationWarning)
9296
def test_rst2html_toctree(self):
9397
fLOG(
9498
__file__,

src/pyquickhelper/helpgen/sphinx_main.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -637,14 +637,15 @@ def lay_build_override_newconf(t3):
637637

638638
if os.path.exists(blog_fold):
639639
fLOG("[generate_help_sphinx] BlogPostList")
640-
plist = BlogPostList(blog_fold, language=language, fLOG=fLOG)
640+
plist = BlogPostList(blog_fold, language=language, fLOG=fLOG,
641+
conf=theconf)
641642
fLOG("[generate_help_sphinx] BlogPostList.write_aggregated")
642-
plist.write_aggregated(blog_fold,
643-
blog_title=theconf.__dict__.get(
644-
"blog_title", project_var_name),
645-
blog_description=theconf.__dict__.get(
646-
"blog_description", "blog associated to " + project_var_name),
647-
blog_root=theconf.__dict__.get("blog_root", "__BLOG_ROOT__"))
643+
plist.write_aggregated(
644+
blog_fold,
645+
blog_title=theconf.__dict__.get("blog_title", project_var_name),
646+
blog_description=theconf.__dict__.get(
647+
"blog_description", "blog associated to " + project_var_name),
648+
blog_root=theconf.__dict__.get("blog_root", "__BLOG_ROOT__"))
648649
else:
649650
plist = None
650651

src/pyquickhelper/sphinxext/blog_post.py

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class BlogPost:
2727
"""
2828

2929
def __init__(self, filename, encoding='utf-8-sig', raise_exception=False,
30-
extensions=None, **kwargs_overrides):
30+
extensions=None, conf=None, **kwargs_overrides):
3131
"""
3232
Creates an instance of a blog post from a file or a string.
3333
@@ -39,6 +39,7 @@ def __init__(self, filename, encoding='utf-8-sig', raise_exception=False,
3939
the content of the blog, if None, it will consider
4040
a default list (see @see cl BlogPost and
4141
@see fn get_default_extensions)
42+
:param conf: existing configuration
4243
:param kwargs_overrides: additional parameters for :epkg:`sphinx`
4344
4445
The constructor creates the following members:
@@ -77,14 +78,16 @@ def __init__(self, filename, encoding='utf-8-sig', raise_exception=False,
7778
overrides["blog_background"] = True
7879
overrides["blog_background_page"] = False
7980
overrides["sharepost"] = None
80-
overrides['epkg_dictionary'] = get_epkg_dictionary()
81+
if conf is None or not getattr(conf, 'epkg_dictionary'):
82+
overrides['epkg_dictionary'] = get_epkg_dictionary()
83+
else:
84+
overrides['epkg_dictionary'] = conf.epkg_dictionary
8185
overrides.update(kwargs_overrides)
8286

8387
overrides.update({ # 'warning_stream': StringIO(),
8488
'out_blogpostlist': [],
8589
'out_runpythonlist': [],
86-
'master_doc': 'stringblog'
87-
})
90+
'master_doc': 'stringblog'})
8891

8992
if "extensions" not in overrides:
9093
if extensions is None:
@@ -97,7 +100,7 @@ def __init__(self, filename, encoding='utf-8-sig', raise_exception=False,
97100
app = MockSphinxApp.create(confoverrides=overrides)
98101
env = app[0].env
99102
config = env.config
100-
103+
101104
if 'blog_background' not in config:
102105
raise AttributeError( # pragma: no cover
103106
"Unable to find 'blog_background' in config:\n{0}".format(
@@ -108,9 +111,9 @@ def __init__(self, filename, encoding='utf-8-sig', raise_exception=False,
108111
"\n".join(sorted(config.values))))
109112
if 'epkg_dictionary' in config:
110113
if len(config.epkg_dictionary) > 0:
111-
overrides['epkg_dictionary'] = config.epkg_dictionary
114+
overrides['epkg_dictionary'].update(config.epkg_dictionary)
112115
else:
113-
overrides['epkg_dictionary'] = get_epkg_dictionary()
116+
overrides['epkg_dictionary'].update(get_epkg_dictionary())
114117

115118
env.temp_data["docname"] = "stringblog"
116119
overrides["env"] = env
@@ -334,8 +337,8 @@ def can_cut(i, r, rows_stack):
334337
last = rows_stack[-1]
335338
if len(last) > 0:
336339
last = last[-1]
337-
if indent == indent2 and len(rs) == 0 and \
338-
last in {'.', ';', ',', ':', '!', '?'}:
340+
if (indent == indent2 and len(rs) == 0 and
341+
last in {'.', ';', ',', ':', '!', '?'}):
339342
return True
340343
rows_stack.append(r)
341344
return False
@@ -345,20 +348,16 @@ def can_cut(i, r, rows_stack):
345348
for i, r in enumerate(self.Content):
346349
rows.append(" " + self._update_link(r))
347350
if cut and can_cut(i, r, rows_stack):
348-
rows.append("")
349-
rows.append(" ...")
351+
rows.extend(["", " ..."])
350352
break
351353
else:
352354
for i, r in enumerate(self.Content):
353355
rows.append(" " + r)
354356
if cut and can_cut(i, r, rows_stack):
355-
rows.append("")
356-
rows.append(" ...")
357+
rows.extend(["", " ..."])
357358
break
358359

359-
rows.append("")
360-
rows.append("")
361-
360+
rows.extend(["", ""])
362361
return "\n".join(rows)
363362

364363
image_tag = ".. image:: "
@@ -379,5 +378,4 @@ def _update_link(self, row):
379378
return row
380379
row = f"{row[:i]}{self.Year}/{r2}"
381380
return row
382-
else:
383-
return row
381+
return row

src/pyquickhelper/sphinxext/blog_post_list.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,20 @@ class BlogPostList:
1818
Defines a list of @see cl BlogPost.
1919
"""
2020

21-
def __init__(self, folder, encoding="utf8", language="en", extensions=None, fLOG=noLOG):
21+
def __init__(self, folder, encoding="utf8", language="en", extensions=None,
22+
conf=None, fLOG=noLOG):
2223
"""
2324
Creates a list of @see cl BlogPost, we assume each blog
2425
post belongs to a subfolder ``YYYY``.
2526
26-
@param folder folder when to find files
27-
@param encoding encoding
28-
@param language language
29-
@param extensions list of extension to use to parse the content of the blog,
30-
if None, it will consider a default list
31-
(@see cl BlogPost and @see fn get_default_extensions)
32-
@param fLOG logging function
27+
:param folder: folder when to find files
28+
:param encoding: encoding
29+
:param language: language
30+
:param extensions: list of extension to use to parse the content
31+
of the blog, if None, it will consider a default list
32+
(@see cl BlogPost and @see fn get_default_extensions)
33+
:param conf: existing configuration
34+
:param fLOG: logging function
3335
"""
3436
self._blogposts = []
3537
sub = os.listdir(folder)
@@ -43,7 +45,7 @@ def __init__(self, folder, encoding="utf8", language="en", extensions=None, fLOG
4345
fpost = os.path.join(full, post)
4446
fLOG(f" reading post {post!r}")
4547
obj = BlogPost(fpost, encoding=encoding,
46-
extensions=extensions)
48+
extensions=extensions, conf=conf)
4749
self._blogposts.append((obj.date, obj))
4850
fLOG(f"[BlogPostList] end reading folder {full!r}")
4951
self._blogposts.sort(reverse=True)

src/pyquickhelper/sphinxext/sphinx_blog_extension.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,9 @@ def run(self):
128128
'lid': self.options.get("lid", self.options.get("label", None)),
129129
}
130130

131-
tag = BlogPost.build_tag(p["date"], p["title"]) if p[
132-
'lid'] is None else p['lid']
131+
tag = BlogPost.build_tag(
132+
p["date"],
133+
p["title"]) if p['lid'] is None else p['lid']
133134
targetnode = nodes.target(p['title'], '', ids=[tag])
134135
p["target"] = targetnode
135136
idbp = tag + "-container"
@@ -140,13 +141,21 @@ def run(self):
140141
env.blogpost_all.append(p)
141142

142143
# build node
143-
node = self.__class__.blogpost_class(ids=[idbp], year=p["date"][:4],
144-
rawfile=self.options.get(
145-
"rawfile", None),
146-
linktitle=p["title"], lg=language_code,
147-
blog_background=p["blog_background"])
148-
149-
return self.fill_node(node, env, tag, p, language_code, targetnode, sharepost)
144+
if not docname:
145+
raise RuntimeError( # pragma: no cover
146+
f'docname is missing in blogpost {docname}.')
147+
node = self.__class__.blogpost_class(
148+
ids=[idbp], year=p["date"][:4],
149+
rawfile=self.options.get("rawfile", None),
150+
linktitle=p["title"], lg=language_code,
151+
blog_background=p["blog_background"])
152+
node.source = docname
153+
if not node.source:
154+
raise RuntimeError( # pragma: no cover
155+
f'node.source is missing in blogpost '
156+
f'{self.options.get("rawfile", None)}.')
157+
return self.fill_node(node, env, tag, p, language_code,
158+
targetnode, sharepost)
150159

151160
def fill_node(self, node, env, tag, p, language_code, targetnode, sharepost):
152161
"""

src/pyquickhelper/sphinxext/sphinx_mathdef_extension.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ def run(self):
259259
self.state.document.settings, "env") else None
260260
tag = self.options.get('tag', '').strip()
261261
contents = self.options.get(
262-
'contents', False) in (True, "True", "true", 1, "1", "", None, "None")
262+
'contents', False) in (True, "True", "true", 1,
263+
"1", "", None, "None")
263264
if env is not None:
264265
targetid = f"indexmathelist-{env.new_serialno('indexmathelist')}"
265266
targetnode = nodes.target('', '', ids=[targetid])

src/pyquickhelper/sphinxext/sphinximages/sphinxtrib/images.py

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,10 @@ def directive_boolean(value):
6161
raise ValueError("No argument provided but required")
6262
if value.lower().strip() in ["yes", "1", 1, "true", "ok"]:
6363
return True
64-
elif value.lower().strip() in ['no', '0', 0, 'false', 'none']:
64+
if value.lower().strip() in ['no', '0', 0, 'false', 'none']:
6565
return False
66-
else:
67-
raise ValueError("Please use on of: yes, true, no, false. "
68-
"Do not use `{}` as boolean.".format(value))
66+
raise ValueError("Please use on of: yes, true, no, false. "
67+
"Do not use `{}` as boolean.".format(value))
6968

7069

7170
def get_image_extension(uri):
@@ -110,7 +109,6 @@ def align(self):
110109
'width': directives.length_or_percentage_or_unitless,
111110
'height': directives.length_or_unitless,
112111
'strech': directives.choice,
113-
114112
'group': directives.unchanged,
115113
'class': directives.class_option, # or str?
116114
'alt': directives.unchanged,
@@ -126,9 +124,9 @@ def run(self):
126124
env = self.state.document.settings.env
127125
conf = env.app.config.images_config
128126

129-
# TODO get defaults from config
130-
group = self.options.get('group',
131-
conf['default_group'] if conf['default_group'] else uuid.uuid4())
127+
group = self.options.get(
128+
'group',
129+
conf['default_group'] if conf['default_group'] else uuid.uuid4())
132130
classes = self.options.get('class', '')
133131
width = self.options.get('width', conf['default_image_width'])
134132
height = self.options.get('height', conf['default_image_height'])
@@ -139,12 +137,9 @@ def run(self):
139137
align = self.options.get('align', '')
140138
show_caption = self.options.get('show_caption', False)
141139
legacy_classes = self.options.get('legacy_class', '')
142-
143-
# TODO get default from config
144140
download = self.options.get('download', conf['download'])
145141

146142
# parse nested content
147-
# TODO: something is broken here, not parsed as expected
148143
description = nodes.paragraph()
149144
content = nodes.paragraph()
150145
content += [nodes.Text(f"{x}") for x in self.content]
@@ -181,6 +176,7 @@ def run(self):
181176

182177
img['content'] = description.astext()
183178
img['target'] = target
179+
img['source'] = "unknown-source"
184180

185181
if title is None:
186182
img['title'] = ''
@@ -196,10 +192,10 @@ def run(self):
196192
img['size'] = (width, height)
197193
img['width'] = width
198194
img['height'] = height
199-
img['classes'] += classes
200195
img['alt'] = alt
201196
img['align'] = align
202197
img['download'] = download
198+
img['classes'] += classes
203199
return [img]
204200

205201
def is_remote(self, uri):
@@ -222,9 +218,8 @@ def is_remote(self, uri):
222218
return False
223219
if '://' in uri:
224220
return True
225-
raise ValueError('Image URI `{}` has to be local relative or '
226-
'absolute path to image, or remote address.'
227-
.format(uri))
221+
raise ValueError(f'Image URI {uri!r} has to be local relative or '
222+
f'absolute path to image, or remote address.')
228223

229224

230225
def install_backend_static_files(app, env):
@@ -282,7 +277,6 @@ def download_images(app, env):
282277
dirn = os.path.dirname(dst)
283278
ensuredir(dirn)
284279
if not os.path.isfile(dst):
285-
286280
logger.info('%r -> %r (downloading)', src, dst)
287281
with open(dst, 'wb') as f:
288282
# TODO: apply reuqests_kwargs
@@ -333,13 +327,17 @@ def inner_wrapper(writer, node):
333327
return f(writer, node)
334328
return inner_wrapper
335329
signature = f'_{node.__name__}_{output_type}'
336-
return (backend_method(getattr(backend, 'visit' + signature, getattr(backend, 'visit_' + node.__name__ + '_fallback'))),
337-
backend_method(getattr(backend, 'depart' + signature, getattr(backend, 'depart_' + node.__name__ + '_fallback'))))
330+
return (backend_method(getattr(backend, 'visit' + signature,
331+
getattr(backend, 'visit_' + node.__name__ + '_fallback'))),
332+
backend_method(getattr(backend, 'depart' + signature,
333+
getattr(backend, 'depart_' + node.__name__ + '_fallback'))))
338334

339335
# add new node to the stack
340336
# connect backend processing methods to this node
341-
app.add_node(image_node, **{output_type: backend_methods(image_node, output_type)
342-
for output_type in ('html', 'latex', 'man', 'texinfo', 'text', 'epub')})
337+
app.add_node(
338+
image_node,
339+
**{output_type: backend_methods(image_node, output_type)
340+
for output_type in ('html', 'latex', 'man', 'texinfo', 'text', 'epub')})
343341

344342
app.add_directive('thumbnail', ImageDirective)
345343
if config['override_image_directive']:

0 commit comments

Comments
 (0)