diff --git a/_unittests/ut_helpgen/test_rst2html_toc.py b/_unittests/ut_helpgen/test_rst2html_toc.py index c80672df..8e941a86 100644 --- a/_unittests/ut_helpgen/test_rst2html_toc.py +++ b/_unittests/ut_helpgen/test_rst2html_toc.py @@ -8,12 +8,14 @@ import unittest from pyquickhelper.loghelper.flog import fLOG -from pyquickhelper.pycode import get_temp_folder, is_travis_or_appveyor +from pyquickhelper.pycode import ( + get_temp_folder, is_travis_or_appveyor, ignore_warnings) from pyquickhelper.helpgen import rst2html class TestRst2HtmlToc(unittest.TestCase): + @ignore_warnings(PendingDeprecationWarning) def test_rst2html_toc(self): fLOG( __file__, @@ -58,6 +60,7 @@ def test_rst2html_toc(self): f.write(text) self.assertIn("* :ref:`title2`", text) + @ignore_warnings(PendingDeprecationWarning) def test_rst2html_autoclass(self): fLOG( __file__, @@ -89,6 +92,7 @@ def test_rst2html_autoclass(self): f.write(text) self.assertIn("* ``:indent:`` to indent the output", text) + @ignore_warnings(PendingDeprecationWarning) def test_rst2html_toctree(self): fLOG( __file__, diff --git a/src/pyquickhelper/helpgen/sphinx_main.py b/src/pyquickhelper/helpgen/sphinx_main.py index 2b330209..630e814a 100644 --- a/src/pyquickhelper/helpgen/sphinx_main.py +++ b/src/pyquickhelper/helpgen/sphinx_main.py @@ -637,14 +637,15 @@ def lay_build_override_newconf(t3): if os.path.exists(blog_fold): fLOG("[generate_help_sphinx] BlogPostList") - plist = BlogPostList(blog_fold, language=language, fLOG=fLOG) + plist = BlogPostList(blog_fold, language=language, fLOG=fLOG, + conf=theconf) fLOG("[generate_help_sphinx] BlogPostList.write_aggregated") - plist.write_aggregated(blog_fold, - blog_title=theconf.__dict__.get( - "blog_title", project_var_name), - blog_description=theconf.__dict__.get( - "blog_description", "blog associated to " + project_var_name), - blog_root=theconf.__dict__.get("blog_root", "__BLOG_ROOT__")) + plist.write_aggregated( + blog_fold, + blog_title=theconf.__dict__.get("blog_title", project_var_name), + blog_description=theconf.__dict__.get( + "blog_description", "blog associated to " + project_var_name), + blog_root=theconf.__dict__.get("blog_root", "__BLOG_ROOT__")) else: plist = None diff --git a/src/pyquickhelper/sphinxext/blog_post.py b/src/pyquickhelper/sphinxext/blog_post.py index dee364c4..e803824e 100644 --- a/src/pyquickhelper/sphinxext/blog_post.py +++ b/src/pyquickhelper/sphinxext/blog_post.py @@ -27,7 +27,7 @@ class BlogPost: """ def __init__(self, filename, encoding='utf-8-sig', raise_exception=False, - extensions=None, **kwargs_overrides): + extensions=None, conf=None, **kwargs_overrides): """ Creates an instance of a blog post from a file or a string. @@ -39,6 +39,7 @@ def __init__(self, filename, encoding='utf-8-sig', raise_exception=False, the content of the blog, if None, it will consider a default list (see @see cl BlogPost and @see fn get_default_extensions) + :param conf: existing configuration :param kwargs_overrides: additional parameters for :epkg:`sphinx` The constructor creates the following members: @@ -77,14 +78,16 @@ def __init__(self, filename, encoding='utf-8-sig', raise_exception=False, overrides["blog_background"] = True overrides["blog_background_page"] = False overrides["sharepost"] = None - overrides['epkg_dictionary'] = get_epkg_dictionary() + if conf is None or not getattr(conf, 'epkg_dictionary'): + overrides['epkg_dictionary'] = get_epkg_dictionary() + else: + overrides['epkg_dictionary'] = conf.epkg_dictionary overrides.update(kwargs_overrides) overrides.update({ # 'warning_stream': StringIO(), 'out_blogpostlist': [], 'out_runpythonlist': [], - 'master_doc': 'stringblog' - }) + 'master_doc': 'stringblog'}) if "extensions" not in overrides: if extensions is None: @@ -97,7 +100,7 @@ def __init__(self, filename, encoding='utf-8-sig', raise_exception=False, app = MockSphinxApp.create(confoverrides=overrides) env = app[0].env config = env.config - + if 'blog_background' not in config: raise AttributeError( # pragma: no cover "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, "\n".join(sorted(config.values)))) if 'epkg_dictionary' in config: if len(config.epkg_dictionary) > 0: - overrides['epkg_dictionary'] = config.epkg_dictionary + overrides['epkg_dictionary'].update(config.epkg_dictionary) else: - overrides['epkg_dictionary'] = get_epkg_dictionary() + overrides['epkg_dictionary'].update(get_epkg_dictionary()) env.temp_data["docname"] = "stringblog" overrides["env"] = env @@ -334,8 +337,8 @@ def can_cut(i, r, rows_stack): last = rows_stack[-1] if len(last) > 0: last = last[-1] - if indent == indent2 and len(rs) == 0 and \ - last in {'.', ';', ',', ':', '!', '?'}: + if (indent == indent2 and len(rs) == 0 and + last in {'.', ';', ',', ':', '!', '?'}): return True rows_stack.append(r) return False @@ -345,20 +348,16 @@ def can_cut(i, r, rows_stack): for i, r in enumerate(self.Content): rows.append(" " + self._update_link(r)) if cut and can_cut(i, r, rows_stack): - rows.append("") - rows.append(" ...") + rows.extend(["", " ..."]) break else: for i, r in enumerate(self.Content): rows.append(" " + r) if cut and can_cut(i, r, rows_stack): - rows.append("") - rows.append(" ...") + rows.extend(["", " ..."]) break - rows.append("") - rows.append("") - + rows.extend(["", ""]) return "\n".join(rows) image_tag = ".. image:: " @@ -379,5 +378,4 @@ def _update_link(self, row): return row row = f"{row[:i]}{self.Year}/{r2}" return row - else: - return row + return row diff --git a/src/pyquickhelper/sphinxext/blog_post_list.py b/src/pyquickhelper/sphinxext/blog_post_list.py index 6eb909dc..9efab141 100644 --- a/src/pyquickhelper/sphinxext/blog_post_list.py +++ b/src/pyquickhelper/sphinxext/blog_post_list.py @@ -18,18 +18,20 @@ class BlogPostList: Defines a list of @see cl BlogPost. """ - def __init__(self, folder, encoding="utf8", language="en", extensions=None, fLOG=noLOG): + def __init__(self, folder, encoding="utf8", language="en", extensions=None, + conf=None, fLOG=noLOG): """ Creates a list of @see cl BlogPost, we assume each blog post belongs to a subfolder ``YYYY``. - @param folder folder when to find files - @param encoding encoding - @param language language - @param extensions list of extension to use to parse the content of the blog, - if None, it will consider a default list - (@see cl BlogPost and @see fn get_default_extensions) - @param fLOG logging function + :param folder: folder when to find files + :param encoding: encoding + :param language: language + :param extensions: list of extension to use to parse the content + of the blog, if None, it will consider a default list + (@see cl BlogPost and @see fn get_default_extensions) + :param conf: existing configuration + :param fLOG: logging function """ self._blogposts = [] sub = os.listdir(folder) @@ -43,7 +45,7 @@ def __init__(self, folder, encoding="utf8", language="en", extensions=None, fLOG fpost = os.path.join(full, post) fLOG(f" reading post {post!r}") obj = BlogPost(fpost, encoding=encoding, - extensions=extensions) + extensions=extensions, conf=conf) self._blogposts.append((obj.date, obj)) fLOG(f"[BlogPostList] end reading folder {full!r}") self._blogposts.sort(reverse=True) diff --git a/src/pyquickhelper/sphinxext/sphinx_blog_extension.py b/src/pyquickhelper/sphinxext/sphinx_blog_extension.py index cfaf1721..fa7dad0a 100644 --- a/src/pyquickhelper/sphinxext/sphinx_blog_extension.py +++ b/src/pyquickhelper/sphinxext/sphinx_blog_extension.py @@ -128,8 +128,9 @@ def run(self): 'lid': self.options.get("lid", self.options.get("label", None)), } - tag = BlogPost.build_tag(p["date"], p["title"]) if p[ - 'lid'] is None else p['lid'] + tag = BlogPost.build_tag( + p["date"], + p["title"]) if p['lid'] is None else p['lid'] targetnode = nodes.target(p['title'], '', ids=[tag]) p["target"] = targetnode idbp = tag + "-container" @@ -140,13 +141,21 @@ def run(self): env.blogpost_all.append(p) # build node - node = self.__class__.blogpost_class(ids=[idbp], year=p["date"][:4], - rawfile=self.options.get( - "rawfile", None), - linktitle=p["title"], lg=language_code, - blog_background=p["blog_background"]) - - return self.fill_node(node, env, tag, p, language_code, targetnode, sharepost) + if not docname: + raise RuntimeError( # pragma: no cover + f'docname is missing in blogpost {docname}.') + node = self.__class__.blogpost_class( + ids=[idbp], year=p["date"][:4], + rawfile=self.options.get("rawfile", None), + linktitle=p["title"], lg=language_code, + blog_background=p["blog_background"]) + node.source = docname + if not node.source: + raise RuntimeError( # pragma: no cover + f'node.source is missing in blogpost ' + f'{self.options.get("rawfile", None)}.') + return self.fill_node(node, env, tag, p, language_code, + targetnode, sharepost) def fill_node(self, node, env, tag, p, language_code, targetnode, sharepost): """ diff --git a/src/pyquickhelper/sphinxext/sphinx_mathdef_extension.py b/src/pyquickhelper/sphinxext/sphinx_mathdef_extension.py index fb74a408..316d521a 100644 --- a/src/pyquickhelper/sphinxext/sphinx_mathdef_extension.py +++ b/src/pyquickhelper/sphinxext/sphinx_mathdef_extension.py @@ -259,7 +259,8 @@ def run(self): self.state.document.settings, "env") else None tag = self.options.get('tag', '').strip() contents = self.options.get( - 'contents', False) in (True, "True", "true", 1, "1", "", None, "None") + 'contents', False) in (True, "True", "true", 1, + "1", "", None, "None") if env is not None: targetid = f"indexmathelist-{env.new_serialno('indexmathelist')}" targetnode = nodes.target('', '', ids=[targetid]) diff --git a/src/pyquickhelper/sphinxext/sphinximages/sphinxtrib/images.py b/src/pyquickhelper/sphinxext/sphinximages/sphinxtrib/images.py index 775a1543..c21beab5 100644 --- a/src/pyquickhelper/sphinxext/sphinximages/sphinxtrib/images.py +++ b/src/pyquickhelper/sphinxext/sphinximages/sphinxtrib/images.py @@ -61,11 +61,10 @@ def directive_boolean(value): raise ValueError("No argument provided but required") if value.lower().strip() in ["yes", "1", 1, "true", "ok"]: return True - elif value.lower().strip() in ['no', '0', 0, 'false', 'none']: + if value.lower().strip() in ['no', '0', 0, 'false', 'none']: return False - else: - raise ValueError("Please use on of: yes, true, no, false. " - "Do not use `{}` as boolean.".format(value)) + raise ValueError("Please use on of: yes, true, no, false. " + "Do not use `{}` as boolean.".format(value)) def get_image_extension(uri): @@ -110,7 +109,6 @@ def align(self): 'width': directives.length_or_percentage_or_unitless, 'height': directives.length_or_unitless, 'strech': directives.choice, - 'group': directives.unchanged, 'class': directives.class_option, # or str? 'alt': directives.unchanged, @@ -126,9 +124,9 @@ def run(self): env = self.state.document.settings.env conf = env.app.config.images_config - # TODO get defaults from config - group = self.options.get('group', - conf['default_group'] if conf['default_group'] else uuid.uuid4()) + group = self.options.get( + 'group', + conf['default_group'] if conf['default_group'] else uuid.uuid4()) classes = self.options.get('class', '') width = self.options.get('width', conf['default_image_width']) height = self.options.get('height', conf['default_image_height']) @@ -139,12 +137,9 @@ def run(self): align = self.options.get('align', '') show_caption = self.options.get('show_caption', False) legacy_classes = self.options.get('legacy_class', '') - - # TODO get default from config download = self.options.get('download', conf['download']) # parse nested content - # TODO: something is broken here, not parsed as expected description = nodes.paragraph() content = nodes.paragraph() content += [nodes.Text(f"{x}") for x in self.content] @@ -181,6 +176,7 @@ def run(self): img['content'] = description.astext() img['target'] = target + img['source'] = "unknown-source" if title is None: img['title'] = '' @@ -196,10 +192,10 @@ def run(self): img['size'] = (width, height) img['width'] = width img['height'] = height - img['classes'] += classes img['alt'] = alt img['align'] = align img['download'] = download + img['classes'] += classes return [img] def is_remote(self, uri): @@ -222,9 +218,8 @@ def is_remote(self, uri): return False if '://' in uri: return True - raise ValueError('Image URI `{}` has to be local relative or ' - 'absolute path to image, or remote address.' - .format(uri)) + raise ValueError(f'Image URI {uri!r} has to be local relative or ' + f'absolute path to image, or remote address.') def install_backend_static_files(app, env): @@ -282,7 +277,6 @@ def download_images(app, env): dirn = os.path.dirname(dst) ensuredir(dirn) if not os.path.isfile(dst): - logger.info('%r -> %r (downloading)', src, dst) with open(dst, 'wb') as f: # TODO: apply reuqests_kwargs @@ -333,13 +327,17 @@ def inner_wrapper(writer, node): return f(writer, node) return inner_wrapper signature = f'_{node.__name__}_{output_type}' - return (backend_method(getattr(backend, 'visit' + signature, getattr(backend, 'visit_' + node.__name__ + '_fallback'))), - backend_method(getattr(backend, 'depart' + signature, getattr(backend, 'depart_' + node.__name__ + '_fallback')))) + return (backend_method(getattr(backend, 'visit' + signature, + getattr(backend, 'visit_' + node.__name__ + '_fallback'))), + backend_method(getattr(backend, 'depart' + signature, + getattr(backend, 'depart_' + node.__name__ + '_fallback')))) # add new node to the stack # connect backend processing methods to this node - app.add_node(image_node, **{output_type: backend_methods(image_node, output_type) - for output_type in ('html', 'latex', 'man', 'texinfo', 'text', 'epub')}) + app.add_node( + image_node, + **{output_type: backend_methods(image_node, output_type) + for output_type in ('html', 'latex', 'man', 'texinfo', 'text', 'epub')}) app.add_directive('thumbnail', ImageDirective) if config['override_image_directive']: