From 7ebb547860a01206b4d2728063dfcd9bc5b380c8 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Tue, 15 Oct 2024 09:39:12 +0200 Subject: [PATCH 01/73] fix: add code --- src/ansys_sphinx_theme/__init__.py | 48 +++++++++++++++++++ .../theme/ansys_sphinx_theme/theme.conf | 3 +- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index e1fc4288a..1f83a9ba1 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -28,6 +28,7 @@ import subprocess from typing import Any, Dict +from docutils import nodes from docutils.nodes import document from sphinx import addnodes from sphinx.application import Sphinx @@ -532,6 +533,51 @@ def check_for_depreciated_theme_options(app: Sphinx): ) +def extract_whatsnew(app, docname, source): + """Extract the what's new content from the document.""" + config_options = app.config.html_theme_options + whats_new_options = config_options.get("whatsnew") + if not whats_new_options: + return + + document_name = whats_new_options.get("file", "whatsnew") + + if docname != document_name: + return + + whatsnew_content = [] + doctree = app.env.get_doctree(docname) + docs_content = doctree.traverse(nodes.section) + for docs_content in docs_content: + contents = { + "title": docs_content[0].astext(), + "children": docs_content.traverse(nodes.paragraph)[0].astext(), + "url": "", + } + whatsnew_content.append(contents) + whats_new_content = [ + content for content in whatsnew_content if content["title"].startswith("v0") + ] + app.env.whatsnew_content = whats_new_content + + +def add_whatsnew(app, pagename, templatename, context, doctree): + """Add what's new section to the context.""" + config_options = app.config.html_theme_options + whats_new_options = config_options.get("whatsnew") + if not whats_new_options: + return + + pages = whats_new_options.get("pages", ["index"]) + + if pagename not in pages: + return + + whatsnew = context.get("whatsnew", []) + whatsnew.extend(app.env.whatsnew_content) + context["whatsnew"] = whatsnew + + def setup(app: Sphinx) -> Dict: """Connect to the Sphinx theme app. @@ -568,6 +614,8 @@ def setup(app: Sphinx) -> Dict: app.connect("builder-inited", configure_theme_logo) app.connect("builder-inited", build_quarto_cheatsheet) app.connect("builder-inited", check_for_depreciated_theme_options) + app.connect("source-read", extract_whatsnew) + app.connect("html-page-context", add_whatsnew) app.connect("html-page-context", update_footer_theme) app.connect("html-page-context", fix_edit_html_page_context) app.connect("html-page-context", add_cheat_sheet) diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/theme.conf b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/theme.conf index 684474f3e..d9bc05936 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/theme.conf +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/theme.conf @@ -17,4 +17,5 @@ footer_end = theme-version.html cheatsheet = ansys_sphinx_theme_autoapi = logo = -static_search = \ No newline at end of file +static_search = +whatsnew = \ No newline at end of file From 4bdd038db02435feeb468a067333b9e86eb9e91f Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Tue, 15 Oct 2024 09:59:33 +0200 Subject: [PATCH 02/73] fix: update the html files --- src/ansys_sphinx_theme/__init__.py | 19 ++++-- .../components/whatsnew_sidebar.html | 61 +++++++++++++++++++ 2 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 1f83a9ba1..7c904b878 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -533,7 +533,9 @@ def check_for_depreciated_theme_options(app: Sphinx): ) -def extract_whatsnew(app, docname, source): +def extract_whatsnew( + app: Sphinx, pagename: str, templatename: str, context: Dict[str, Any], doctree +): """Extract the what's new content from the document.""" config_options = app.config.html_theme_options whats_new_options = config_options.get("whatsnew") @@ -542,11 +544,11 @@ def extract_whatsnew(app, docname, source): document_name = whats_new_options.get("file", "whatsnew") - if docname != document_name: + if pagename != document_name: return whatsnew_content = [] - doctree = app.env.get_doctree(docname) + doctree = app.env.get_doctree(pagename) docs_content = doctree.traverse(nodes.section) for docs_content in docs_content: contents = { @@ -570,12 +572,22 @@ def add_whatsnew(app, pagename, templatename, context, doctree): pages = whats_new_options.get("pages", ["index"]) + extract_whatsnew(app, pagename, templatename, context, doctree) + + print(app.env.whatsnew_content) + + print("here=======================") + exit(1) + if pagename not in pages: return whatsnew = context.get("whatsnew", []) whatsnew.extend(app.env.whatsnew_content) context["whatsnew"] = whatsnew + sidebar = context.get("sidebars", []) + sidebar.append("whatsnew_sidebar.html") + context["sidebars"] = sidebar def setup(app: Sphinx) -> Dict: @@ -614,7 +626,6 @@ def setup(app: Sphinx) -> Dict: app.connect("builder-inited", configure_theme_logo) app.connect("builder-inited", build_quarto_cheatsheet) app.connect("builder-inited", check_for_depreciated_theme_options) - app.connect("source-read", extract_whatsnew) app.connect("html-page-context", add_whatsnew) app.connect("html-page-context", update_footer_theme) app.connect("html-page-context", fix_edit_html_page_context) diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html new file mode 100644 index 000000000..53a68c26a --- /dev/null +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html @@ -0,0 +1,61 @@ +
+

What's New

+
    + {% for whatsnew in whatsnew %} + {% set title = whatsnew.get('title') %} + {% set url = whatsnew.get('url') %} + {% set children = whatsnew.get('children') %} +
  • + {{ title }} + +
  • + {% endfor %} +
+
+ + From 98736911e84afac72fd9e995a4f6c4c31692efe8 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Tue, 15 Oct 2024 10:41:35 +0200 Subject: [PATCH 03/73] fix: update the events --- src/ansys_sphinx_theme/__init__.py | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 7c904b878..d63a2e6b6 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -533,9 +533,7 @@ def check_for_depreciated_theme_options(app: Sphinx): ) -def extract_whatsnew( - app: Sphinx, pagename: str, templatename: str, context: Dict[str, Any], doctree -): +def extract_whatsnew(app, doctree): """Extract the what's new content from the document.""" config_options = app.config.html_theme_options whats_new_options = config_options.get("whatsnew") @@ -544,12 +542,9 @@ def extract_whatsnew( document_name = whats_new_options.get("file", "whatsnew") - if pagename != document_name: - return - + get_doctree = app.env.get_doctree(document_name) whatsnew_content = [] - doctree = app.env.get_doctree(pagename) - docs_content = doctree.traverse(nodes.section) + docs_content = get_doctree.traverse(nodes.section) for docs_content in docs_content: contents = { "title": docs_content[0].astext(), @@ -571,14 +566,6 @@ def add_whatsnew(app, pagename, templatename, context, doctree): return pages = whats_new_options.get("pages", ["index"]) - - extract_whatsnew(app, pagename, templatename, context, doctree) - - print(app.env.whatsnew_content) - - print("here=======================") - exit(1) - if pagename not in pages: return @@ -626,6 +613,7 @@ def setup(app: Sphinx) -> Dict: app.connect("builder-inited", configure_theme_logo) app.connect("builder-inited", build_quarto_cheatsheet) app.connect("builder-inited", check_for_depreciated_theme_options) + app.connect("doctree-read", extract_whatsnew) app.connect("html-page-context", add_whatsnew) app.connect("html-page-context", update_footer_theme) app.connect("html-page-context", fix_edit_html_page_context) From 307315fff059d30df1efa8f342db6ce7b7ce853d Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Tue, 15 Oct 2024 13:52:21 +0200 Subject: [PATCH 04/73] fix: update the styles --- src/ansys_sphinx_theme/__init__.py | 6 +-- .../components/whatsnew_sidebar.html | 46 +------------------ .../static/css/whatsnew.css | 44 ++++++++++++++++++ 3 files changed, 49 insertions(+), 47 deletions(-) create mode 100644 src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index d63a2e6b6..de7520bf5 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -533,15 +533,15 @@ def check_for_depreciated_theme_options(app: Sphinx): ) -def extract_whatsnew(app, doctree): +def extract_whatsnew(app, doctree, docname): """Extract the what's new content from the document.""" config_options = app.config.html_theme_options + whats_new_options = config_options.get("whatsnew") if not whats_new_options: return document_name = whats_new_options.get("file", "whatsnew") - get_doctree = app.env.get_doctree(document_name) whatsnew_content = [] docs_content = get_doctree.traverse(nodes.section) @@ -613,7 +613,7 @@ def setup(app: Sphinx) -> Dict: app.connect("builder-inited", configure_theme_logo) app.connect("builder-inited", build_quarto_cheatsheet) app.connect("builder-inited", check_for_depreciated_theme_options) - app.connect("doctree-read", extract_whatsnew) + app.connect("doctree-resolved", extract_whatsnew) app.connect("html-page-context", add_whatsnew) app.connect("html-page-context", update_footer_theme) app.connect("html-page-context", fix_edit_html_page_context) diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html index 53a68c26a..e5cfe1c96 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html @@ -14,48 +14,6 @@

What's New

{% endfor %} - + + diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css new file mode 100644 index 000000000..79059bd98 --- /dev/null +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css @@ -0,0 +1,44 @@ +.whatsnew-sidebar { + border: 1px solid var(--ast-color-table-inner-border); + padding: 8px; + background-color: var(--pst-color-background); + border-radius: 10px; + /* box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); */ + margin-bottom: 20px; +} + +.whatsnew-sidebar h2 { + font-size: 1em; + font-family: var(--ast-font-family-base); + font-weight: bold; + margin-bottom: 10px; + margin-top: 10px; +} + +.whatsnew-sidebar ul { + list-style: none; + padding-left: 0; /* Remove default padding */ +} + +.whatsnew-sidebar li { + margin-bottom: 10px; /* Space between versions */ +} + +.whatsnew-sidebar li ul { + margin-left: 15px; /* Indent sub-items */ +} + +.whatsnew-sidebar li ul li { + list-style-type: disc; /* Bullet points */ + margin-left: 20px; /* Spacing for bullet points */ +} + +.whatsnew-sidebar a { + text-decoration: none; /* Remove underline */ + color: var(--ast-color-link); /* Blue link color */ +} + +.whatsnew-sidebar a:hover { + text-decoration: underline; /* Underline on hover */ + color: var(--ast-color-link-hover); /* Blue link color on hover */ +} From 1b1fd8653f501b187f501f223c66155bcf01afb0 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Tue, 15 Oct 2024 16:22:14 +0200 Subject: [PATCH 05/73] fix: update --- src/ansys_sphinx_theme/__init__.py | 23 ++++++++++++------- .../components/whatsnew_sidebar.html | 5 +++- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index de7520bf5..bb5c06423 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -543,18 +543,25 @@ def extract_whatsnew(app, doctree, docname): document_name = whats_new_options.get("file", "whatsnew") get_doctree = app.env.get_doctree(document_name) - whatsnew_content = [] + whats_new_content = [] docs_content = get_doctree.traverse(nodes.section) - for docs_content in docs_content: + selected_docs = [ + doc_content for doc_content in docs_content if doc_content[0].astext().startswith("v0") + ] + for docs_content in selected_docs: + children_section_headers = [child for child in docs_content.traverse(nodes.section)] + headers = [child[0].astext() for child in children_section_headers] + # if not more than one content, then children is the 2nd and 3rd , if not get paragraph + if len(children_section_headers) > 1: + children = headers[1:] + else: + children = [docs_content.traverse(nodes.paragraph)[0].astext()] contents = { "title": docs_content[0].astext(), - "children": docs_content.traverse(nodes.paragraph)[0].astext(), - "url": "", + "children": children, + "url": f"{document_name}.html#{docs_content['ids'][0]}", } - whatsnew_content.append(contents) - whats_new_content = [ - content for content in whatsnew_content if content["title"].startswith("v0") - ] + whats_new_content.append(contents) app.env.whatsnew_content = whats_new_content diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html index e5cfe1c96..6a22c08c0 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html @@ -8,7 +8,10 @@

What's New

  • {{ title }}
  • {% endfor %} From 4f612804571147aee0c995075903618a548d04d3 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Tue, 29 Oct 2024 14:57:00 +0100 Subject: [PATCH 06/73] fix: update the styles --- src/ansys_sphinx_theme/__init__.py | 6 +++++- .../components/whatsnew_sidebar.html | 3 +-- .../ansys_sphinx_theme/static/css/whatsnew.css | 17 +++++++++++++---- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index bb5c06423..cb3da9121 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -540,7 +540,7 @@ def extract_whatsnew(app, doctree, docname): whats_new_options = config_options.get("whatsnew") if not whats_new_options: return - + no_of_contents = whats_new_options.get("no_of_headers", 3) document_name = whats_new_options.get("file", "whatsnew") get_doctree = app.env.get_doctree(document_name) whats_new_content = [] @@ -562,6 +562,10 @@ def extract_whatsnew(app, doctree, docname): "url": f"{document_name}.html#{docs_content['ids'][0]}", } whats_new_content.append(contents) + + if len(whats_new_content) > no_of_contents: + whats_new_content = whats_new_content[:no_of_contents] + app.env.whatsnew_content = whats_new_content diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html index 6a22c08c0..6664c4e3a 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html @@ -7,12 +7,11 @@

    What's New

    {% set children = whatsnew.get('children') %}
  • {{ title }} -
      {% for child in children %} +
    • {{ child }}
    • {% endfor %} -
  • {% endfor %} diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css index 79059bd98..01f2ff6d3 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css @@ -1,8 +1,8 @@ .whatsnew-sidebar { - border: 1px solid var(--ast-color-table-inner-border); + /* border: 1px solid var(--ast-color-table-inner-border); */ padding: 8px; background-color: var(--pst-color-background); - border-radius: 10px; + /* border-radius: 10px; */ /* box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); */ margin-bottom: 20px; } @@ -24,6 +24,15 @@ margin-bottom: 10px; /* Space between versions */ } +.whatsnew-sidebar li:hover { + color: var(--ast-color-text); + background: var(--ast-sidebar-active-background); + text-decoration: none; + box-shadow: 1px 1px 2px 0px var(--ast-sidebar-active-background); + border-radius: var(--ast-sphinx-design-border-radius); + font-weight: bold; +} + .whatsnew-sidebar li ul { margin-left: 15px; /* Indent sub-items */ } @@ -35,10 +44,10 @@ .whatsnew-sidebar a { text-decoration: none; /* Remove underline */ - color: var(--ast-color-link); /* Blue link color */ + color: var(--ast-color-text); /* Blue link color */ } .whatsnew-sidebar a:hover { text-decoration: underline; /* Underline on hover */ - color: var(--ast-color-link-hover); /* Blue link color on hover */ + color: var(--ast-color-text); /* Blue link color on hover */ } From d56e39eb2e02bc97da32da9f3660334a989abb83 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Tue, 29 Oct 2024 17:39:54 +0100 Subject: [PATCH 07/73] fix: update the styles --- .../components/whatsnew_sidebar.html | 13 ++++++------- .../ansys_sphinx_theme/static/css/whatsnew.css | 2 ++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html index 6664c4e3a..27d125230 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html @@ -5,14 +5,13 @@

    What's New

    {% set title = whatsnew.get('title') %} {% set url = whatsnew.get('url') %} {% set children = whatsnew.get('children') %} -
  • - {{ title }} + + {{ title }} - {% for child in children %} - -
  • {{ child }}
  • - {% endfor %} - + {% for child in children %} +
  • {{ child }}
  • + {% endfor %} + {% endfor %} diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css index 01f2ff6d3..9f6272544 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css @@ -18,10 +18,12 @@ .whatsnew-sidebar ul { list-style: none; padding-left: 0; /* Remove default padding */ + line-height: 30px; } .whatsnew-sidebar li { margin-bottom: 10px; /* Space between versions */ + padding: 4px 24px 4px 32px; } .whatsnew-sidebar li:hover { From 1534c650bfbfe59c16b60acdf7dfdbd2e8d32474 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Thu, 31 Oct 2024 10:37:49 +0000 Subject: [PATCH 08/73] chore: adding changelog file 574.miscellaneous.md [dependabot-skip] --- doc/changelog.d/574.miscellaneous.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/574.miscellaneous.md diff --git a/doc/changelog.d/574.miscellaneous.md b/doc/changelog.d/574.miscellaneous.md new file mode 100644 index 000000000..2baa1536a --- /dev/null +++ b/doc/changelog.d/574.miscellaneous.md @@ -0,0 +1 @@ +feat: whatsnew theme option \ No newline at end of file From 3e555eb6bf5d80d72435db4a67008068ef2c709a Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Mon, 4 Nov 2024 12:14:18 +0100 Subject: [PATCH 09/73] test: whatsnew --- doc/changelog.d/changelog_template.jinja | 11 +++++++++++ doc/changelog.d/whatsnew/123.whatsnew.md | 4 ++++ doc/changelog.d/whatsnew/456.whatsnew.md | Bin 0 -> 56 bytes doc/changelog.d/whatsnew/678.whatsnew.md | Bin 0 -> 1076 bytes pyproject.toml | 9 +++++++++ 5 files changed, 24 insertions(+) create mode 100644 doc/changelog.d/whatsnew/123.whatsnew.md create mode 100644 doc/changelog.d/whatsnew/456.whatsnew.md create mode 100644 doc/changelog.d/whatsnew/678.whatsnew.md diff --git a/doc/changelog.d/changelog_template.jinja b/doc/changelog.d/changelog_template.jinja index c5fe4e7da..1e6d6d81d 100644 --- a/doc/changelog.d/changelog_template.jinja +++ b/doc/changelog.d/changelog_template.jinja @@ -1,3 +1,14 @@ +{% for category, val in sections["Whatsnew"].items() %} +{{ category }} +{% set underline = '^' * category|length %} +{{ underline }} + +{% for text, values in val.items() %} +- {{ text }} +{% endfor %} + +{% endfor %} + {% if sections[""] %} {% for category, val in definitions.items() if category in sections[""] %} diff --git a/doc/changelog.d/whatsnew/123.whatsnew.md b/doc/changelog.d/whatsnew/123.whatsnew.md new file mode 100644 index 000000000..98d456ec6 --- /dev/null +++ b/doc/changelog.d/whatsnew/123.whatsnew.md @@ -0,0 +1,4 @@ +## Something + +- Something new +- Something else \ No newline at end of file diff --git a/doc/changelog.d/whatsnew/456.whatsnew.md b/doc/changelog.d/whatsnew/456.whatsnew.md new file mode 100644 index 0000000000000000000000000000000000000000..2b83dff1702e6bb8900e7255de342bb403df5c94 GIT binary patch literal 56 zcmezWubd%+A(5ekL4hHYAq`9_Fr)z4DGYgF(Q<|&Ag_cW6)2a;kOPFg3|tHVdfy8e literal 0 HcmV?d00001 diff --git a/doc/changelog.d/whatsnew/678.whatsnew.md b/doc/changelog.d/whatsnew/678.whatsnew.md new file mode 100644 index 0000000000000000000000000000000000000000..9367debae9eb1fee61ec274e49f4b46b3619fcd6 GIT binary patch literal 1076 zcmb7@O-{ow5QX0wi96&1pGQrgc;wbzEyg z_Pf!jcjW$ZQs*UT;Tg1y3@)kTJ-vFmjs=}H_Eu)p++NMn_l@<~vHPy6p}n4Q{bTQb Vj(<&WC;Ycq*6|_p7wi9cegQfAxBmbD literal 0 HcmV?d00001 diff --git a/pyproject.toml b/pyproject.toml index ee0249173..8ec57c231 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -163,3 +163,12 @@ showcontent = true directory = "test" name = "Test" showcontent = true + +[[tool.towncrier.type]] +directory = "whatsnew" +name = "Whatsnew" +showcontent = true + +[[tool.towncrier.section]] +name = "Whatsnew" +path = "whatsnew" From 0a7ea4f96cda0c086387f7f69026f66b14105424 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Mon, 4 Nov 2024 15:38:48 +0100 Subject: [PATCH 10/73] fix: testing --- doc/changelog.d/changelog_template.jinja | 15 ++++++++++++--- doc/changelog.d/whatsnew/456.whatsnew.md | Bin 56 -> 96 bytes doc/changelog.d/whatsnew/678.whatsnew.md | Bin 1076 -> 1132 bytes 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/doc/changelog.d/changelog_template.jinja b/doc/changelog.d/changelog_template.jinja index 1e6d6d81d..6d5b468d3 100644 --- a/doc/changelog.d/changelog_template.jinja +++ b/doc/changelog.d/changelog_template.jinja @@ -3,10 +3,19 @@ {% set underline = '^' * category|length %} {{ underline }} -{% for text, values in val.items() %} -- {{ text }} -{% endfor %} +{%- for text, values in val.items() -%} +{# get first line of text #} +{% set heading = text.split('\n')[0] -%} +{# get remaining text #} +{% set remaining_text = text.split('\n')[1:] %} +{# join remaining text #} +{% set remaining_text = remaining_text|join('\n') %} + +**{{ heading }}** +{{ remaining_text }} + +{% endfor %} {% endfor %} {% if sections[""] %} diff --git a/doc/changelog.d/whatsnew/456.whatsnew.md b/doc/changelog.d/whatsnew/456.whatsnew.md index 2b83dff1702e6bb8900e7255de342bb403df5c94..57e6f27abb2e2a9d0668d277a6865e3d1e9916c7 100644 GIT binary patch literal 96 zcmezWPnkiPL4hHJA%h{4p%}=5kcmK62}3GSq=bQ&feVa7p!`gRJce|jd?HvqNM$lZ VK2WTLp$MouiJ=t8$_KJR`T%0v5X=Ao literal 56 zcmezWubd%+A(5ekL4hHYAq`9_Fr)z4DGYgF(Q<|&Ag_cW6)2a;kOPFg3|tHVdfy8e diff --git a/doc/changelog.d/whatsnew/678.whatsnew.md b/doc/changelog.d/whatsnew/678.whatsnew.md index 9367debae9eb1fee61ec274e49f4b46b3619fcd6..fd73333c989675789e71201fb306208cfcecebc0 100644 GIT binary patch delta 67 zcmdnO@rJ|d|37601%?uaREA<8slbp4CG)_d89;t9kd?-e&rrmW%a90^jcpN From 97b05ce0a35f27b29bbe2b23b1877542216382e5 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Tue, 5 Nov 2024 14:47:18 +0100 Subject: [PATCH 11/73] fix more template --- doc/changelog.d/changelog_template.jinja | 19 +++++++++++++++++++ doc/changelog.d/whatsnew/123.whatsnew.md | 4 ---- doc/changelog.d/whatsnew/456.whatsnew.md | Bin 96 -> 1208 bytes doc/changelog.d/whatsnew/678.whatsnew.md | Bin 1132 -> 0 bytes doc/changelog.d/whatsnew/whatsnew.md | 22 ++++++++++++++++++++++ 5 files changed, 41 insertions(+), 4 deletions(-) delete mode 100644 doc/changelog.d/whatsnew/123.whatsnew.md delete mode 100644 doc/changelog.d/whatsnew/678.whatsnew.md create mode 100644 doc/changelog.d/whatsnew/whatsnew.md diff --git a/doc/changelog.d/changelog_template.jinja b/doc/changelog.d/changelog_template.jinja index 6d5b468d3..d4b868bf6 100644 --- a/doc/changelog.d/changelog_template.jinja +++ b/doc/changelog.d/changelog_template.jinja @@ -15,12 +15,31 @@ {{ remaining_text }} + .. tab-item:: {{ heading}} + + .. list-table:: + :header-rows: 0 + :widths: auto + + {{ remaining_text|indent(9) }} + {% endfor %} {% endfor %} {% if sections[""] %} {% for category, val in definitions.items() if category in sections[""] %} + .. tab-item:: {{ category }} + + .. list-table:: + :header-rows: 0 + :widths: auto + + {%- for text, values in sections[""][category].items() %} + * - {{ text }} + - {{ values|join(', ') }} + {%- endfor %} + {{ definitions[category]['name'] }} {% set underline = '^' * definitions[category]['name']|length %} {{ underline }} diff --git a/doc/changelog.d/whatsnew/123.whatsnew.md b/doc/changelog.d/whatsnew/123.whatsnew.md deleted file mode 100644 index 98d456ec6..000000000 --- a/doc/changelog.d/whatsnew/123.whatsnew.md +++ /dev/null @@ -1,4 +0,0 @@ -## Something - -- Something new -- Something else \ No newline at end of file diff --git a/doc/changelog.d/whatsnew/456.whatsnew.md b/doc/changelog.d/whatsnew/456.whatsnew.md index 57e6f27abb2e2a9d0668d277a6865e3d1e9916c7..67b3ecc6ad75580d5aaede25b9d40d696da8f12f 100644 GIT binary patch literal 1208 zcmbtU!A`Y)n%jiZ@0)y!_ati-#{)gP5IoIs*UkP z&K1w(j^pV=%af=-Q03D6@~o8FiDjy4!HOD@O}Eat9CcUB@wniU(_6b+#q8vc<9>-b z&nn(jZiqiHGZ10U+V3693{^c+uKJp?+L(nYb+~MuXSlN69{R>F?wFU^%_fX$;*Rl5 zr{q9%thW>Q_aJDF;;fB{5@#qe{p5)H;K?=X_#yA)-q|_095lsW6DlkzPg$=PrQE!6 zJRP7f;smpa3W52#`P2M;y$D+r_R9#c6retD1$6h(y+N`K= ob56q{oUVpJtH%z%V;@3J?%$XSy$PDm5!I%DpJS@^W@{oo08#z6>;M1& literal 96 zcmezWPnkiPL4hHJA%h{4p%}=5kcmK62}3GSq=bQ&feVa7p!`gRJce|jd?HvqNM$lZ VK2WTLp$MouiJ=t8$_KJR`T%0v5X=Ao diff --git a/doc/changelog.d/whatsnew/678.whatsnew.md b/doc/changelog.d/whatsnew/678.whatsnew.md deleted file mode 100644 index fd73333c989675789e71201fb306208cfcecebc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1132 zcmb7^%}&Bl5QWd$#CK@ox;%h8^3 z=T7Q&Gu~5wV%mn`^ESJB?b8 z)61E1&^4G4o(R3BqOGsZV(JzrnS5d_HpCP2DJHY09rKim%-^n#?!M_Yr##Jwv%I-; zr^(QIW_OVCm^Q0_se5-1K8Qe{@S9HoyT@v~j<&bdc=xP{-t0zv3oWU3m=CqDFqRwlLsD3w?^^w}&dv#vJHod@>P{B1mKGCcFK4x^*&|4Yf qd8suB>l^E_bN5~1p?y8W`p3Te3GpSp9r3$${{(Zi$NFadU!FhzJiw&@ diff --git a/doc/changelog.d/whatsnew/whatsnew.md b/doc/changelog.d/whatsnew/whatsnew.md new file mode 100644 index 000000000..ee81b2446 --- /dev/null +++ b/doc/changelog.d/whatsnew/whatsnew.md @@ -0,0 +1,22 @@ +Launch GUI +^^^^^^^^^^ + +Open the current project with Mechanical GUI. + +.. code:: python + + from ansys.mechanical.core import App + + app = App() + app.save() + app.launch_gui() + +Above code opens up the temporarily saved ``.mechdb`` or ``.mechdat`` files. +The files are deleted when GUI is closed . For more info check +`launch_gui() <../api/ansys/mechanical/core/embedding/launch_gui/index.html>`_ function + +Opens up the specified project file. + +.. code:: python + + launch_gui("path/to/project.mechdb") \ No newline at end of file From e53147ac03f178a6e56bfd1f4f894e4e81f8cb3f Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Thu, 7 Nov 2024 10:54:58 +0100 Subject: [PATCH 12/73] fix: add whatsnew --- doc/changelog.d/changelog_template.jinja | 68 +++++++----------- .../whatsnew/{whatsnew.md => 123.whatsnew.md} | 3 +- doc/changelog.d/whatsnew/456.whatsnew.md | Bin 1208 -> 311 bytes pyproject.toml | 8 ++- 4 files changed, 31 insertions(+), 48 deletions(-) rename doc/changelog.d/whatsnew/{whatsnew.md => 123.whatsnew.md} (97%) diff --git a/doc/changelog.d/changelog_template.jinja b/doc/changelog.d/changelog_template.jinja index d4b868bf6..cc79160e0 100644 --- a/doc/changelog.d/changelog_template.jinja +++ b/doc/changelog.d/changelog_template.jinja @@ -1,56 +1,36 @@ -{% for category, val in sections["Whatsnew"].items() %} -{{ category }} -{% set underline = '^' * category|length %} -{{ underline }} - -{%- for text, values in val.items() -%} -{# get first line of text #} -{% set heading = text.split('\n')[0] -%} -{# get remaining text #} -{% set remaining_text = text.split('\n')[1:] %} -{# join remaining text #} -{% set remaining_text = remaining_text|join('\n') %} - -**{{ heading }}** - -{{ remaining_text }} - - .. tab-item:: {{ heading}} - - .. list-table:: - :header-rows: 0 - :widths: auto +{% if sections["Whatsnew"] %} + {%+ for category, val in sections["Whatsnew"].items() +%} + {%+ if definitions.get(category) and definitions[category].get('name') +%} +{{ definitions[category]['name'] }} +{{ "~" * definitions[category]['name']|length }} + {% endif %} + {%- for text, values in sections["Whatsnew"][category].items() %} - {{ remaining_text|indent(9) }} +{{ text }} -{% endfor %} -{% endfor %} + {% endfor -%} + {% endfor %} +{% endif %} {% if sections[""] %} -{% for category, val in definitions.items() if category in sections[""] %} - - .. tab-item:: {{ category }} - .. list-table:: - :header-rows: 0 - :widths: auto +Changelog +--------- - {%- for text, values in sections[""][category].items() %} - * - {{ text }} - - {{ values|join(', ') }} - {%- endfor %} +.. tab-set:: + {%+ for category, val in definitions.items() if category in sections[""] +%} + .. tab-item:: {{ definitions[category]['name'] }} -{{ definitions[category]['name'] }} -{% set underline = '^' * definitions[category]['name']|length %} -{{ underline }} + .. list-table:: + :header-rows: 0 + :widths: auto -{% for text, values in sections[""][category].items() %} -- {{ text }} {{ values|join(', ') }} -{% endfor %} + {%+ for text, values in sections[""][category].items() +%} + * - {{ text }} + - {{ values|join(', ') }} + {% endfor %} + {% endfor %} -{% endfor %} {% else %} No significant changes. - - {% endif %} diff --git a/doc/changelog.d/whatsnew/whatsnew.md b/doc/changelog.d/whatsnew/123.whatsnew.md similarity index 97% rename from doc/changelog.d/whatsnew/whatsnew.md rename to doc/changelog.d/whatsnew/123.whatsnew.md index ee81b2446..c177772ef 100644 --- a/doc/changelog.d/whatsnew/whatsnew.md +++ b/doc/changelog.d/whatsnew/123.whatsnew.md @@ -1,6 +1,5 @@ Launch GUI -^^^^^^^^^^ - +---------- Open the current project with Mechanical GUI. .. code:: python diff --git a/doc/changelog.d/whatsnew/456.whatsnew.md b/doc/changelog.d/whatsnew/456.whatsnew.md index 67b3ecc6ad75580d5aaede25b9d40d696da8f12f..210d24e45aa70b9086ba62f8c8b0a8212a6e90be 100644 GIT binary patch literal 311 zcmaJ-F>V7f4BPz*j>+N&1n7{lLxB#R8z?@dc5$%;Nr&KmUtfZBYqbcXM1tbGwH}T) zE|q#KG(%0kxdg(P)93${K5BDZm|`);%z;%FI5VO$DmSB2+YtRjKd09K%`WgNH^;5= zAR4Gc&UY6>-WOG4cb*`IE|F8p8AT>O9H47d=_vv2s$xT~`|A1n`%o@2ypdyrwmVYA i%YDj6)!qI9Y)n%jiZ@0)y!_ati-#{)gP5IoIs*UkP z&K1w(j^pV=%af=-Q03D6@~o8FiDjy4!HOD@O}Eat9CcUB@wniU(_6b+#q8vc<9>-b z&nn(jZiqiHGZ10U+V3693{^c+uKJp?+L(nYb+~MuXSlN69{R>F?wFU^%_fX$;*Rl5 zr{q9%thW>Q_aJDF;;fB{5@#qe{p5)H;K?=X_#yA)-q|_095lsW6DlkzPg$=PrQE!6 zJRP7f;smpa3W52#`P2M;y$D+r_R9#c6retD1$6h(y+N`K= ob56q{oUVpJtH%z%V;@3J?%$XSy$PDm5!I%DpJS@^W@{oo08#z6>;M1& diff --git a/pyproject.toml b/pyproject.toml index 8ec57c231..6ef66bcbf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,7 +126,7 @@ issue_format = "`#{issue} Date: Thu, 7 Nov 2024 11:04:11 +0100 Subject: [PATCH 13/73] fix: add the release notes --- doc/source/changelog.rst | 11 +++++++++++ doc/source/index.rst | 4 ++-- doc/source/release-note.rst | 23 +++++++++++++++++++++++ pyproject.toml | 2 +- 4 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 doc/source/release-note.rst diff --git a/doc/source/changelog.rst b/doc/source/changelog.rst index 92673d715..d8d3974a4 100644 --- a/doc/source/changelog.rst +++ b/doc/source/changelog.rst @@ -1,8 +1,19 @@ +:orphan: + .. _ref_release_notes: Release notes ############# + +.. button-ref:: release-note + :ref-type: doc + :color: primary + :shadow: + :expand: + + Go to latest release notes + This document contains the release notes for the project. .. vale off diff --git a/doc/source/index.rst b/doc/source/index.rst index b85d7ffc9..37838c0bb 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -37,7 +37,7 @@ are included in the theme to make documentation more appealing and user-friendly {% endif %} .. grid-item-card:: :material-regular:`update;1.25em` Changelog - :link: changelog + :link: release-note :link-type: doc View the changelog for this project. @@ -53,4 +53,4 @@ are included in the theme to make documentation more appealing and user-friendly {% if build_examples %} examples.rst {% endif %} - changelog + release-note.rst diff --git a/doc/source/release-note.rst b/doc/source/release-note.rst new file mode 100644 index 000000000..d99a7bbdf --- /dev/null +++ b/doc/source/release-note.rst @@ -0,0 +1,23 @@ + +Release notes +############# + +This document contains the release notes for the project. + +.. vale off + +.. towncrier release notes start + +.. vale on + +Older release notes +==================== + + +.. button-ref:: changelog + :ref-type: doc + :color: primary + :shadow: + :expand: + + Go to older release notes \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 6ef66bcbf..d4945d2fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -118,7 +118,7 @@ show_missing = true [tool.towncrier] directory = "doc/changelog.d" -filename = "doc/source/changelog.rst" +filename = "doc/source/release-note.rst" template = "doc/changelog.d/changelog_template.jinja" start_string = ".. towncrier release notes start\n" title_format = "`{version} `_ - {project_date}" From 7272126511ab6577ffe52a1d2e727604e365570b Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Thu, 7 Nov 2024 11:20:35 +0100 Subject: [PATCH 14/73] fix: spacing --- doc/changelog.d/whatsnew/{123.whatsnew.md => 123.whatsnew.rst} | 0 doc/changelog.d/whatsnew/{456.whatsnew.md => 456.whatsnew.rst} | 2 +- pyproject.toml | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) rename doc/changelog.d/whatsnew/{123.whatsnew.md => 123.whatsnew.rst} (100%) rename doc/changelog.d/whatsnew/{456.whatsnew.md => 456.whatsnew.rst} (93%) diff --git a/doc/changelog.d/whatsnew/123.whatsnew.md b/doc/changelog.d/whatsnew/123.whatsnew.rst similarity index 100% rename from doc/changelog.d/whatsnew/123.whatsnew.md rename to doc/changelog.d/whatsnew/123.whatsnew.rst diff --git a/doc/changelog.d/whatsnew/456.whatsnew.md b/doc/changelog.d/whatsnew/456.whatsnew.rst similarity index 93% rename from doc/changelog.d/whatsnew/456.whatsnew.md rename to doc/changelog.d/whatsnew/456.whatsnew.rst index 210d24e45..778938f2c 100644 --- a/doc/changelog.d/whatsnew/456.whatsnew.md +++ b/doc/changelog.d/whatsnew/456.whatsnew.rst @@ -9,4 +9,4 @@ It also shows whether an object is suppressed or not. app = mech.App() app.update_globals(globals()) - app.print_tree() + app.print_tree() \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index d4945d2fc..cb571d3fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -123,6 +123,7 @@ template = "doc/changelog.d/changelog_template.jinja" start_string = ".. towncrier release notes start\n" title_format = "`{version} `_ - {project_date}" issue_format = "`#{issue} `_" +all_bullets = false [[tool.towncrier.type]] directory = "added" From 3a53b08028677e4855ce13064432e38f8c1de875 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Thu, 7 Nov 2024 15:42:56 +0100 Subject: [PATCH 15/73] fix: whatsnew --- doc/source/conf.py | 4 ++ doc/source/release-note.rst | 89 ++++++++++++++++++++++++++++++ pyproject.toml | 2 +- src/ansys_sphinx_theme/__init__.py | 57 +++++++++++-------- 4 files changed, 129 insertions(+), 23 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 1e3f8c135..7617ddca2 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -66,6 +66,10 @@ "limit": 7, "minMatchCharLength": 3, }, + "whatsnew": { + "file": "release-note", + "pages": ["index", "release-note"], + }, } index_patterns = { diff --git a/doc/source/release-note.rst b/doc/source/release-note.rst index d99a7bbdf..df5366ae9 100644 --- a/doc/source/release-note.rst +++ b/doc/source/release-note.rst @@ -8,6 +8,95 @@ This document contains the release notes for the project. .. towncrier release notes start +Version `v0.12.0 `_ (2024-11-07) +============================================================================================= + + +Whatsnew +~~~~~~~~ + +Launch GUI +---------- +Open the current project with Mechanical GUI. + +.. code:: python + + from ansys.mechanical.core import App + + app = App() + app.save() + app.launch_gui() + +Above code opens up the temporarily saved ``.mechdb`` or ``.mechdat`` files. +The files are deleted when GUI is closed . For more info check +`launch_gui() <../api/ansys/mechanical/core/embedding/launch_gui/index.html>`_ function + +Opens up the specified project file. + +.. code:: python + + launch_gui("path/to/project.mechdb") + + +Prints Mechanical project tree +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +This feature let you see the heirachial Mechanical project tree. +It also shows whether an object is suppressed or not. + +.. code:: python + + import ansys.mechanical.core as mech + + app = mech.App() + app.update_globals(globals()) + app.print_tree() + + + +Changelog +--------- + +.. tab-set:: + + .. tab-item:: Dependencies + + .. list-table:: + :header-rows: 0 + :widths: auto + + + * - chore(deps): bump pygithub from 2.4.0 to 2.5.0 + - `#582 `_ + + .. tab-item:: Miscellaneous + + .. list-table:: + :header-rows: 0 + :widths: auto + + + * - feat: whatsnew theme option + - `#574 `_ + + * - chore: bump version 1.3.dev0 + - `#577 `_ + + * - fix: CONTRIBUTORS.md + - `#578 `_ + + .. tab-item:: Documentation + + .. list-table:: + :header-rows: 0 + :widths: auto + + + * - chore: update CHANGELOG for v1.2.0 + - `#576 `_ + + * - Enable 'show_prev_next' in the documented defaults + - `#580 `_ + .. vale on Older release notes diff --git a/pyproject.toml b/pyproject.toml index 74ab324df..b68fe3967 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -121,7 +121,7 @@ directory = "doc/changelog.d" filename = "doc/source/release-note.rst" template = "doc/changelog.d/changelog_template.jinja" start_string = ".. towncrier release notes start\n" -title_format = "`{version} `_ - {project_date}" +title_format = "Version `{version} `_ ({project_date})" issue_format = "`#{issue} `_" all_bullets = false diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 89b8bb00a..9b54291c1 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -29,7 +29,6 @@ from typing import Any, Dict from docutils import nodes - from sphinx import addnodes from sphinx.application import Sphinx @@ -547,30 +546,44 @@ def extract_whatsnew(app, doctree, docname): if not whats_new_options: return no_of_contents = whats_new_options.get("no_of_headers", 3) - document_name = whats_new_options.get("file", "whatsnew") + document_name = whats_new_options.get("file", "release-note") get_doctree = app.env.get_doctree(document_name) whats_new_content = [] docs_content = get_doctree.traverse(nodes.section) - selected_docs = [ - doc_content for doc_content in docs_content if doc_content[0].astext().startswith("v0") - ] - for docs_content in selected_docs: - children_section_headers = [child for child in docs_content.traverse(nodes.section)] - headers = [child[0].astext() for child in children_section_headers] - # if not more than one content, then children is the 2nd and 3rd , if not get paragraph - if len(children_section_headers) > 1: - children = headers[1:] - else: - children = [docs_content.traverse(nodes.paragraph)[0].astext()] - contents = { - "title": docs_content[0].astext(), - "children": children, - "url": f"{document_name}.html#{docs_content['ids'][0]}", - } - whats_new_content.append(contents) - - if len(whats_new_content) > no_of_contents: - whats_new_content = whats_new_content[:no_of_contents] + if not docs_content: + return + + versions_nodes = [node for node in docs_content if node.get("ids")[0].startswith("version")] + + # get the version nodes upto the specified number of headers + versions_nodes = versions_nodes[:no_of_contents] + + if versions_nodes: + for version_node in versions_nodes: + title = version_node[0].astext() + + sections = list(version_node.traverse(nodes.section)) + + whats_new_nodes = [node for node in sections if node.get("ids")[0] == "whatsnew"] + + if whats_new_nodes: + children = [node for node in whats_new_nodes[0].traverse(nodes.section)] + + headers = [child[0].astext() for child in children] + + if len(children) > 1: + children = headers[1:] + + else: + children = [whats_new_nodes[0].traverse(nodes.paragraph)[0].astext()] + + contents = { + "title": title, + "children": children, + "url": f"{document_name}.html#{whats_new_nodes[0]['ids'][0]}", + } + + whats_new_content.append(contents) app.env.whatsnew_content = whats_new_content From 282c04c1de9ce2f6764d111324087d946a5f0013 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Thu, 7 Nov 2024 14:45:07 +0000 Subject: [PATCH 16/73] chore: adding changelog file 583.documentation.md [dependabot-skip] --- doc/changelog.d/583.documentation.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/583.documentation.md diff --git a/doc/changelog.d/583.documentation.md b/doc/changelog.d/583.documentation.md new file mode 100644 index 000000000..5d41c5bb0 --- /dev/null +++ b/doc/changelog.d/583.documentation.md @@ -0,0 +1 @@ +docs: whatsnew jinja template testing \ No newline at end of file From 0db35d33d3ac11dd8316213712df42cc9e0676cc Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Thu, 7 Nov 2024 15:51:07 +0100 Subject: [PATCH 17/73] fix: vale --- doc/source/release-note.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/release-note.rst b/doc/source/release-note.rst index df5366ae9..0acdf390d 100644 --- a/doc/source/release-note.rst +++ b/doc/source/release-note.rst @@ -38,9 +38,9 @@ Opens up the specified project file. launch_gui("path/to/project.mechdb") -Prints Mechanical project tree +Prints mechanical project tree ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -This feature let you see the heirachial Mechanical project tree. +This feature let you see the hierarchy of the mechanical project. It also shows whether an object is suppressed or not. .. code:: python From 302efaa3ce69231426393ff7012c03d8e69b3273 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Thu, 7 Nov 2024 16:11:28 +0100 Subject: [PATCH 18/73] fix: vale --- doc/changelog.d/whatsnew/456.whatsnew.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/changelog.d/whatsnew/456.whatsnew.rst b/doc/changelog.d/whatsnew/456.whatsnew.rst index 778938f2c..33f7d42cd 100644 --- a/doc/changelog.d/whatsnew/456.whatsnew.rst +++ b/doc/changelog.d/whatsnew/456.whatsnew.rst @@ -1,6 +1,6 @@ -Prints Mechanical project tree +Prints mechanical project tree ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -This feature let you see the heirachial Mechanical project tree. +This feature let you see the hierarchy of the mechanical project. It also shows whether an object is suppressed or not. .. code:: python From 24efa327b89a412f2e9ff82450644de41ae3c906 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Tue, 12 Nov 2024 10:51:08 +0100 Subject: [PATCH 19/73] fix: header levels --- doc/changelog.d/changelog_template.jinja | 2 +- doc/changelog.d/whatsnew/123.whatsnew.rst | 2 +- doc/source/release-note.rst | 11 +++++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/doc/changelog.d/changelog_template.jinja b/doc/changelog.d/changelog_template.jinja index cc79160e0..4b51b88b9 100644 --- a/doc/changelog.d/changelog_template.jinja +++ b/doc/changelog.d/changelog_template.jinja @@ -2,7 +2,7 @@ {%+ for category, val in sections["Whatsnew"].items() +%} {%+ if definitions.get(category) and definitions[category].get('name') +%} {{ definitions[category]['name'] }} -{{ "~" * definitions[category]['name']|length }} +{{ "-" * definitions[category]['name']|length }} {% endif %} {%- for text, values in sections["Whatsnew"][category].items() %} diff --git a/doc/changelog.d/whatsnew/123.whatsnew.rst b/doc/changelog.d/whatsnew/123.whatsnew.rst index c177772ef..cd895c207 100644 --- a/doc/changelog.d/whatsnew/123.whatsnew.rst +++ b/doc/changelog.d/whatsnew/123.whatsnew.rst @@ -1,5 +1,5 @@ Launch GUI ----------- +^^^^^^^^^^ Open the current project with Mechanical GUI. .. code:: python diff --git a/doc/source/release-note.rst b/doc/source/release-note.rst index 0acdf390d..83c6ef547 100644 --- a/doc/source/release-note.rst +++ b/doc/source/release-note.rst @@ -8,15 +8,15 @@ This document contains the release notes for the project. .. towncrier release notes start -Version `v0.12.0 `_ (2024-11-07) -============================================================================================= +Version `0.12.0 `_ (November 12, 2024) +================================================================================================== Whatsnew -~~~~~~~~ +-------- Launch GUI ----------- +^^^^^^^^^^ Open the current project with Mechanical GUI. .. code:: python @@ -97,6 +97,9 @@ Changelog * - Enable 'show_prev_next' in the documented defaults - `#580 `_ + * - docs: whatsnew jinja template testing + - `#583 `_ + .. vale on Older release notes From 4b587e283455e9ee5146d4bfa02c6da6f78ad01e Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Wed, 13 Nov 2024 09:42:50 +0100 Subject: [PATCH 20/73] fix: test with style --- src/ansys_sphinx_theme/__init__.py | 3 ++ .../components/whatsnew_sidebar.html | 20 +++++++++++-- .../static/css/whatsnew.css | 28 +++++++++++++++++-- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 9b54291c1..3f2531b0a 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -571,6 +571,8 @@ def extract_whatsnew(app, doctree, docname): headers = [child[0].astext() for child in children] + # header_anchors = [child.get("ids")[0] for child in children] + if len(children) > 1: children = headers[1:] @@ -579,6 +581,7 @@ def extract_whatsnew(app, doctree, docname): contents = { "title": title, + "title_url": f"{document_name}.html#{version_node.get('ids')[0]}", "children": children, "url": f"{document_name}.html#{whats_new_nodes[0]['ids'][0]}", } diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html index 27d125230..81f2fb8df 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html @@ -4,10 +4,12 @@

    What's New

    {% for whatsnew in whatsnew %} {% set title = whatsnew.get('title') %} {% set url = whatsnew.get('url') %} + {% set title_url = whatsnew.get('title_url') %} {% set children = whatsnew.get('children') %} +

    {{ title }}

    + - {{ title }} - + {% for child in children %}
  • {{ child }}
  • {% endfor %} @@ -18,3 +20,17 @@

    What's New

    + + + diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css index 9f6272544..07f33179b 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css @@ -15,14 +15,38 @@ margin-top: 10px; } +.whatsnew-sidebar h3 { + font-size: 1em; + font-family: var(--ast-font-family-base); + font-weight: bold; +} + +.whatsnew-sidebar a.current { + color: var(--ast-color-text); + background: var(--ast-sidebar-active-background); + text-decoration: none; + box-shadow: 1px 1px 2px 0px var(--ast-sidebar-active-background); + border-radius: var(--ast-sphinx-design-border-radius); + font-weight: bold; + padding: 4px 24px 4px 32px; +} + +.whatsnew-sidebar h3:hover { + color: var(--ast-color-text); + background: var(--ast-sidebar-active-background); + text-decoration: none; + box-shadow: 1px 1px 2px 0px var(--ast-sidebar-active-background); + border-radius: var(--ast-sphinx-design-border-radius); + font-weight: bold; +} + .whatsnew-sidebar ul { list-style: none; - padding-left: 0; /* Remove default padding */ + padding-left: 12px; /* Remove default padding */ line-height: 30px; } .whatsnew-sidebar li { - margin-bottom: 10px; /* Space between versions */ padding: 4px 24px 4px 32px; } From 9428fa94cd188b39d4f4b343cf0a8b9f4bd7f5ec Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Wed, 13 Nov 2024 12:11:53 +0100 Subject: [PATCH 21/73] fix: add templates --- src/ansys_sphinx_theme/templates/__init__.py | 23 ++++++++++++ .../templates/changelog_template.jinja | 36 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/ansys_sphinx_theme/templates/__init__.py create mode 100644 src/ansys_sphinx_theme/templates/changelog_template.jinja diff --git a/src/ansys_sphinx_theme/templates/__init__.py b/src/ansys_sphinx_theme/templates/__init__.py new file mode 100644 index 000000000..920b91de7 --- /dev/null +++ b/src/ansys_sphinx_theme/templates/__init__.py @@ -0,0 +1,23 @@ +# Copyright (C) 2021 - 2024 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""Reusable templates for changelog files.""" diff --git a/src/ansys_sphinx_theme/templates/changelog_template.jinja b/src/ansys_sphinx_theme/templates/changelog_template.jinja new file mode 100644 index 000000000..4b51b88b9 --- /dev/null +++ b/src/ansys_sphinx_theme/templates/changelog_template.jinja @@ -0,0 +1,36 @@ +{% if sections["Whatsnew"] %} + {%+ for category, val in sections["Whatsnew"].items() +%} + {%+ if definitions.get(category) and definitions[category].get('name') +%} +{{ definitions[category]['name'] }} +{{ "-" * definitions[category]['name']|length }} + {% endif %} + {%- for text, values in sections["Whatsnew"][category].items() %} + +{{ text }} + + {% endfor -%} + {% endfor %} +{% endif %} + +{% if sections[""] %} + +Changelog +--------- + +.. tab-set:: + {%+ for category, val in definitions.items() if category in sections[""] +%} + .. tab-item:: {{ definitions[category]['name'] }} + + .. list-table:: + :header-rows: 0 + :widths: auto + + {%+ for text, values in sections[""][category].items() +%} + * - {{ text }} + - {{ values|join(', ') }} + {% endfor %} + {% endfor %} + +{% else %} +No significant changes. +{% endif %} From 7bc10be7659d2f5d9c89d68af3f188e9a7960349 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Fri, 15 Nov 2024 11:11:03 +0100 Subject: [PATCH 22/73] fix: cleanup the code --- .github/workflows/ci_cd.yml | 10 ++ doc/changelog.d/changelog_template.jinja | 36 -------- doc/changelog.d/whatsnew/123.whatsnew.rst | 21 ----- doc/changelog.d/whatsnew/456.whatsnew.rst | 12 --- doc/source/release-note.rst | 92 ------------------- pyproject.toml | 5 +- src/ansys_sphinx_theme/__init__.py | 45 +++++---- .../components/whatsnew_sidebar.html | 18 +--- .../static/css/whatsnew.css | 5 +- 9 files changed, 45 insertions(+), 199 deletions(-) delete mode 100644 doc/changelog.d/changelog_template.jinja delete mode 100644 doc/changelog.d/whatsnew/123.whatsnew.rst delete mode 100644 doc/changelog.d/whatsnew/456.whatsnew.rst diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 6cac9cdd6..ce2624f62 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -45,6 +45,16 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: + - name: "Setup python" + uses: actions/setup-python@v2 + with: + python-version: ${{ env.MAIN_PYTHON_VERSION }} + + - name: "Install dependencies" + run: | + python -m pip install --upgrade pip + pip install -e .[changelog] + - uses: ansys/actions/doc-changelog@v8 if: ${{ github.event_name == 'pull_request' }} with: diff --git a/doc/changelog.d/changelog_template.jinja b/doc/changelog.d/changelog_template.jinja deleted file mode 100644 index 4b51b88b9..000000000 --- a/doc/changelog.d/changelog_template.jinja +++ /dev/null @@ -1,36 +0,0 @@ -{% if sections["Whatsnew"] %} - {%+ for category, val in sections["Whatsnew"].items() +%} - {%+ if definitions.get(category) and definitions[category].get('name') +%} -{{ definitions[category]['name'] }} -{{ "-" * definitions[category]['name']|length }} - {% endif %} - {%- for text, values in sections["Whatsnew"][category].items() %} - -{{ text }} - - {% endfor -%} - {% endfor %} -{% endif %} - -{% if sections[""] %} - -Changelog ---------- - -.. tab-set:: - {%+ for category, val in definitions.items() if category in sections[""] +%} - .. tab-item:: {{ definitions[category]['name'] }} - - .. list-table:: - :header-rows: 0 - :widths: auto - - {%+ for text, values in sections[""][category].items() +%} - * - {{ text }} - - {{ values|join(', ') }} - {% endfor %} - {% endfor %} - -{% else %} -No significant changes. -{% endif %} diff --git a/doc/changelog.d/whatsnew/123.whatsnew.rst b/doc/changelog.d/whatsnew/123.whatsnew.rst deleted file mode 100644 index cd895c207..000000000 --- a/doc/changelog.d/whatsnew/123.whatsnew.rst +++ /dev/null @@ -1,21 +0,0 @@ -Launch GUI -^^^^^^^^^^ -Open the current project with Mechanical GUI. - -.. code:: python - - from ansys.mechanical.core import App - - app = App() - app.save() - app.launch_gui() - -Above code opens up the temporarily saved ``.mechdb`` or ``.mechdat`` files. -The files are deleted when GUI is closed . For more info check -`launch_gui() <../api/ansys/mechanical/core/embedding/launch_gui/index.html>`_ function - -Opens up the specified project file. - -.. code:: python - - launch_gui("path/to/project.mechdb") \ No newline at end of file diff --git a/doc/changelog.d/whatsnew/456.whatsnew.rst b/doc/changelog.d/whatsnew/456.whatsnew.rst deleted file mode 100644 index 33f7d42cd..000000000 --- a/doc/changelog.d/whatsnew/456.whatsnew.rst +++ /dev/null @@ -1,12 +0,0 @@ -Prints mechanical project tree -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -This feature let you see the hierarchy of the mechanical project. -It also shows whether an object is suppressed or not. - -.. code:: python - - import ansys.mechanical.core as mech - - app = mech.App() - app.update_globals(globals()) - app.print_tree() \ No newline at end of file diff --git a/doc/source/release-note.rst b/doc/source/release-note.rst index 83c6ef547..d99a7bbdf 100644 --- a/doc/source/release-note.rst +++ b/doc/source/release-note.rst @@ -8,98 +8,6 @@ This document contains the release notes for the project. .. towncrier release notes start -Version `0.12.0 `_ (November 12, 2024) -================================================================================================== - - -Whatsnew --------- - -Launch GUI -^^^^^^^^^^ -Open the current project with Mechanical GUI. - -.. code:: python - - from ansys.mechanical.core import App - - app = App() - app.save() - app.launch_gui() - -Above code opens up the temporarily saved ``.mechdb`` or ``.mechdat`` files. -The files are deleted when GUI is closed . For more info check -`launch_gui() <../api/ansys/mechanical/core/embedding/launch_gui/index.html>`_ function - -Opens up the specified project file. - -.. code:: python - - launch_gui("path/to/project.mechdb") - - -Prints mechanical project tree -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -This feature let you see the hierarchy of the mechanical project. -It also shows whether an object is suppressed or not. - -.. code:: python - - import ansys.mechanical.core as mech - - app = mech.App() - app.update_globals(globals()) - app.print_tree() - - - -Changelog ---------- - -.. tab-set:: - - .. tab-item:: Dependencies - - .. list-table:: - :header-rows: 0 - :widths: auto - - - * - chore(deps): bump pygithub from 2.4.0 to 2.5.0 - - `#582 `_ - - .. tab-item:: Miscellaneous - - .. list-table:: - :header-rows: 0 - :widths: auto - - - * - feat: whatsnew theme option - - `#574 `_ - - * - chore: bump version 1.3.dev0 - - `#577 `_ - - * - fix: CONTRIBUTORS.md - - `#578 `_ - - .. tab-item:: Documentation - - .. list-table:: - :header-rows: 0 - :widths: auto - - - * - chore: update CHANGELOG for v1.2.0 - - `#576 `_ - - * - Enable 'show_prev_next' in the documented defaults - - `#580 `_ - - * - docs: whatsnew jinja template testing - - `#583 `_ - .. vale on Older release notes diff --git a/pyproject.toml b/pyproject.toml index b68fe3967..1d2240efa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,9 @@ doc = [ "sphinx-jinja==2.0.2", "sphinx-notfound-page==1.0.4", ] +changelog = [ + "sphinx-design==0.6.1", +] [project.entry-points."sphinx.html_themes"] ansys_sphinx_theme = "ansys_sphinx_theme" @@ -119,7 +122,7 @@ show_missing = true [tool.towncrier] directory = "doc/changelog.d" filename = "doc/source/release-note.rst" -template = "doc/changelog.d/changelog_template.jinja" +template = "ansys_sphinx_theme:changelog_template.jinja" start_string = ".. towncrier release notes start\n" title_format = "Version `{version} `_ ({project_date})" issue_format = "`#{issue} `_" diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 3f2531b0a..a18ddf3fc 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -550,6 +550,8 @@ def extract_whatsnew(app, doctree, docname): get_doctree = app.env.get_doctree(document_name) whats_new_content = [] docs_content = get_doctree.traverse(nodes.section) + app.env.whatsnew_content = [] + if not docs_content: return @@ -558,35 +560,38 @@ def extract_whatsnew(app, doctree, docname): # get the version nodes upto the specified number of headers versions_nodes = versions_nodes[:no_of_contents] - if versions_nodes: - for version_node in versions_nodes: - title = version_node[0].astext() + if not versions_nodes: + return + + for version_node in versions_nodes: + title = version_node[0].astext() + sections = list(version_node.traverse(nodes.section)) - sections = list(version_node.traverse(nodes.section)) + whats_new_nodes = [node for node in sections if node[0].astext().lower() == "whatsnew"] - whats_new_nodes = [node for node in sections if node.get("ids")[0] == "whatsnew"] + if not whats_new_nodes: + continue - if whats_new_nodes: - children = [node for node in whats_new_nodes[0].traverse(nodes.section)] + children = [node for node in whats_new_nodes[0].traverse(nodes.section)] - headers = [child[0].astext() for child in children] + headers = [child[0].astext() for child in children] - # header_anchors = [child.get("ids")[0] for child in children] + # header_anchors = [child.get("ids")[0] for child in children] - if len(children) > 1: - children = headers[1:] + if len(children) > 1: + children = headers[1:] - else: - children = [whats_new_nodes[0].traverse(nodes.paragraph)[0].astext()] + else: + children = [whats_new_nodes[0].traverse(nodes.paragraph)[0].astext()] - contents = { - "title": title, - "title_url": f"{document_name}.html#{version_node.get('ids')[0]}", - "children": children, - "url": f"{document_name}.html#{whats_new_nodes[0]['ids'][0]}", - } + contents = { + "title": title, + "title_url": f"{document_name}.html#{version_node.get('ids')[0]}", + "children": children, + "url": f"{document_name}.html#{whats_new_nodes[0]['ids'][0]}", + } - whats_new_content.append(contents) + whats_new_content.append(contents) app.env.whatsnew_content = whats_new_content diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html index 81f2fb8df..2a2c050ba 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html @@ -1,3 +1,4 @@ +{% if whatsnew %}

    What's New

      @@ -6,7 +7,7 @@

      What's New

      {% set url = whatsnew.get('url') %} {% set title_url = whatsnew.get('title_url') %} {% set children = whatsnew.get('children') %} -

      {{ title }}

      +

      {{ title }}

      @@ -20,17 +21,4 @@

      {{ title }}

      - - - +{% endif %} diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css index 07f33179b..604a4cef5 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/static/css/whatsnew.css @@ -10,15 +10,16 @@ .whatsnew-sidebar h2 { font-size: 1em; font-family: var(--ast-font-family-base); - font-weight: bold; margin-bottom: 10px; margin-top: 10px; + padding: 4px; } .whatsnew-sidebar h3 { font-size: 1em; font-family: var(--ast-font-family-base); - font-weight: bold; + margin: 8px 4px; + padding: 4px 8px; } .whatsnew-sidebar a.current { From 3ba40c19bd6ff30375e6f4636bbf2c1326523d1d Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Fri, 15 Nov 2024 11:14:51 +0100 Subject: [PATCH 23/73] fix: checkout the repo --- .github/workflows/ci_cd.yml | 3 +++ doc/changelog.d/574.miscellaneous.md | 1 - doc/changelog.d/583.documentation.md | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) delete mode 100644 doc/changelog.d/574.miscellaneous.md delete mode 100644 doc/changelog.d/583.documentation.md diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index ce2624f62..6d0d9826f 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -50,6 +50,9 @@ jobs: with: python-version: ${{ env.MAIN_PYTHON_VERSION }} + - name: "Checkout repo" + uses: actions/checkout@v4 + - name: "Install dependencies" run: | python -m pip install --upgrade pip diff --git a/doc/changelog.d/574.miscellaneous.md b/doc/changelog.d/574.miscellaneous.md deleted file mode 100644 index 2baa1536a..000000000 --- a/doc/changelog.d/574.miscellaneous.md +++ /dev/null @@ -1 +0,0 @@ -feat: whatsnew theme option \ No newline at end of file diff --git a/doc/changelog.d/583.documentation.md b/doc/changelog.d/583.documentation.md deleted file mode 100644 index 5d41c5bb0..000000000 --- a/doc/changelog.d/583.documentation.md +++ /dev/null @@ -1 +0,0 @@ -docs: whatsnew jinja template testing \ No newline at end of file From 0659f57e522528ea638272f60f309fc1d60fb897 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Fri, 15 Nov 2024 10:15:54 +0000 Subject: [PATCH 24/73] chore: adding changelog file 583.documentation.md [dependabot-skip] --- doc/changelog.d/583.documentation.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/583.documentation.md diff --git a/doc/changelog.d/583.documentation.md b/doc/changelog.d/583.documentation.md new file mode 100644 index 000000000..ab73b83e0 --- /dev/null +++ b/doc/changelog.d/583.documentation.md @@ -0,0 +1 @@ +feat: add whatsnew options \ No newline at end of file From 67d4468e1fea8e9b87487160670babd2aa104154 Mon Sep 17 00:00:00 2001 From: Revathy Venugopal <104772255+Revathyvenugopal162@users.noreply.github.com> Date: Fri, 15 Nov 2024 11:23:18 +0100 Subject: [PATCH 25/73] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1d2240efa..5bb24b834 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -124,7 +124,7 @@ directory = "doc/changelog.d" filename = "doc/source/release-note.rst" template = "ansys_sphinx_theme:changelog_template.jinja" start_string = ".. towncrier release notes start\n" -title_format = "Version `{version} `_ ({project_date})" +title_format = "Version `{version} `_ ({project_date})" issue_format = "`#{issue} `_" all_bullets = false From b0b9d5cfcf7b39eee60552ce6ac0bf84d344fa7e Mon Sep 17 00:00:00 2001 From: Revathy Venugopal <104772255+Revathyvenugopal162@users.noreply.github.com> Date: Mon, 18 Nov 2024 09:32:22 +0100 Subject: [PATCH 26/73] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jorge Martínez <28702884+jorgepiloto@users.noreply.github.com> --- .github/workflows/ci_cd.yml | 2 +- src/ansys_sphinx_theme/__init__.py | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index 6d0d9826f..705edc3ec 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -46,7 +46,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Setup python" - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ env.MAIN_PYTHON_VERSION }} diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index a18ddf3fc..bf815afba 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -547,9 +547,9 @@ def extract_whatsnew(app, doctree, docname): return no_of_contents = whats_new_options.get("no_of_headers", 3) document_name = whats_new_options.get("file", "release-note") - get_doctree = app.env.get_doctree(document_name) + doctree = app.env.get_doctree(document_name) whats_new_content = [] - docs_content = get_doctree.traverse(nodes.section) + docs_content = doctree.traverse(nodes.section) app.env.whatsnew_content = [] if not docs_content: @@ -576,11 +576,9 @@ def extract_whatsnew(app, doctree, docname): headers = [child[0].astext() for child in children] - # header_anchors = [child.get("ids")[0] for child in children] if len(children) > 1: children = headers[1:] - else: children = [whats_new_nodes[0].traverse(nodes.paragraph)[0].astext()] From e942c61ed992b1d8c3b47ee7ba7a780c55ffeafe Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Mon, 18 Nov 2024 10:14:32 +0100 Subject: [PATCH 27/73] fix: update templates and remove releasenote.rst --- doc/source/changelog.rst | 12 ---------- doc/source/conf.py | 4 ++-- doc/source/index.rst | 4 ++-- doc/source/release-note.rst | 23 ------------------- pyproject.toml | 3 ++- .../templates/changelog_template.jinja | 4 ++-- 6 files changed, 8 insertions(+), 42 deletions(-) delete mode 100644 doc/source/release-note.rst diff --git a/doc/source/changelog.rst b/doc/source/changelog.rst index 8707f98c4..61450778c 100644 --- a/doc/source/changelog.rst +++ b/doc/source/changelog.rst @@ -1,21 +1,9 @@ -:orphan: .. _ref_release_notes: Release notes ############# - -.. button-ref:: release-note - :ref-type: doc - :color: primary - :shadow: - :expand: - - Go to latest release notes - -This document contains the release notes for the project. - .. vale off .. towncrier release notes start diff --git a/doc/source/conf.py b/doc/source/conf.py index 7617ddca2..4b0905079 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -67,8 +67,8 @@ "minMatchCharLength": 3, }, "whatsnew": { - "file": "release-note", - "pages": ["index", "release-note"], + "file": "changelog", + "pages": ["index", "changelog"], }, } diff --git a/doc/source/index.rst b/doc/source/index.rst index 37838c0bb..b85d7ffc9 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -37,7 +37,7 @@ are included in the theme to make documentation more appealing and user-friendly {% endif %} .. grid-item-card:: :material-regular:`update;1.25em` Changelog - :link: release-note + :link: changelog :link-type: doc View the changelog for this project. @@ -53,4 +53,4 @@ are included in the theme to make documentation more appealing and user-friendly {% if build_examples %} examples.rst {% endif %} - release-note.rst + changelog diff --git a/doc/source/release-note.rst b/doc/source/release-note.rst deleted file mode 100644 index d99a7bbdf..000000000 --- a/doc/source/release-note.rst +++ /dev/null @@ -1,23 +0,0 @@ - -Release notes -############# - -This document contains the release notes for the project. - -.. vale off - -.. towncrier release notes start - -.. vale on - -Older release notes -==================== - - -.. button-ref:: changelog - :ref-type: doc - :color: primary - :shadow: - :expand: - - Go to older release notes \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 1d2240efa..560cf63c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -121,12 +121,13 @@ show_missing = true [tool.towncrier] directory = "doc/changelog.d" -filename = "doc/source/release-note.rst" +filename = "doc/source/changelog.rst" template = "ansys_sphinx_theme:changelog_template.jinja" start_string = ".. towncrier release notes start\n" title_format = "Version `{version} `_ ({project_date})" issue_format = "`#{issue} `_" all_bullets = false +underlines = ["^"] [[tool.towncrier.type]] directory = "added" diff --git a/src/ansys_sphinx_theme/templates/changelog_template.jinja b/src/ansys_sphinx_theme/templates/changelog_template.jinja index 4b51b88b9..3fa952fb6 100644 --- a/src/ansys_sphinx_theme/templates/changelog_template.jinja +++ b/src/ansys_sphinx_theme/templates/changelog_template.jinja @@ -2,7 +2,7 @@ {%+ for category, val in sections["Whatsnew"].items() +%} {%+ if definitions.get(category) and definitions[category].get('name') +%} {{ definitions[category]['name'] }} -{{ "-" * definitions[category]['name']|length }} +{% set underline = underlines[0] if underlines else '^' %}{{ underline * definitions[category]['name']|length }} {% endif %} {%- for text, values in sections["Whatsnew"][category].items() %} @@ -15,7 +15,7 @@ {% if sections[""] %} Changelog ---------- +{% set underline = underlines[0] if underlines else '^' %}{{ underline * 8 }} .. tab-set:: {%+ for category, val in definitions.items() if category in sections[""] +%} From a59818382f825d4c3f411610a6140c9eef3b353e Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Mon, 18 Nov 2024 10:17:21 +0100 Subject: [PATCH 28/73] fix: update underline --- pyproject.toml | 2 +- src/ansys_sphinx_theme/templates/changelog_template.jinja | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3d8a0ac15..a7f4b0b2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -127,7 +127,7 @@ start_string = ".. towncrier release notes start\n" title_format = "Version `{version} `_ ({project_date})" issue_format = "`#{issue} `_" all_bullets = false -underlines = ["^"] +underlines = ["=", "^"] [[tool.towncrier.type]] directory = "added" diff --git a/src/ansys_sphinx_theme/templates/changelog_template.jinja b/src/ansys_sphinx_theme/templates/changelog_template.jinja index 3fa952fb6..73d01f600 100644 --- a/src/ansys_sphinx_theme/templates/changelog_template.jinja +++ b/src/ansys_sphinx_theme/templates/changelog_template.jinja @@ -15,7 +15,7 @@ {% if sections[""] %} Changelog -{% set underline = underlines[0] if underlines else '^' %}{{ underline * 8 }} +{% set underline = underlines[0] if underlines else '^' %}{{ underline * 9 }} .. tab-set:: {%+ for category, val in definitions.items() if category in sections[""] +%} From 122c850b3f6952185ec1bb678c9b017435bf8ba9 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Mon, 18 Nov 2024 10:21:13 +0100 Subject: [PATCH 29/73] fix: rename whatsnew_contents o whatsnew --- src/ansys_sphinx_theme/__init__.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index bf815afba..6f23dd9eb 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -548,9 +548,9 @@ def extract_whatsnew(app, doctree, docname): no_of_contents = whats_new_options.get("no_of_headers", 3) document_name = whats_new_options.get("file", "release-note") doctree = app.env.get_doctree(document_name) - whats_new_content = [] + whatsnew = [] docs_content = doctree.traverse(nodes.section) - app.env.whatsnew_content = [] + app.env.whatsnew = [] if not docs_content: return @@ -567,31 +567,30 @@ def extract_whatsnew(app, doctree, docname): title = version_node[0].astext() sections = list(version_node.traverse(nodes.section)) - whats_new_nodes = [node for node in sections if node[0].astext().lower() == "whatsnew"] + whatsnew_nodes = [node for node in sections if node[0].astext().lower() == "whatsnew"] - if not whats_new_nodes: + if not whatsnew_nodes: continue - children = [node for node in whats_new_nodes[0].traverse(nodes.section)] + children = [node for node in whatsnew_nodes[0].traverse(nodes.section)] headers = [child[0].astext() for child in children] - if len(children) > 1: children = headers[1:] else: - children = [whats_new_nodes[0].traverse(nodes.paragraph)[0].astext()] + children = [whatsnew_nodes[0].traverse(nodes.paragraph)[0].astext()] contents = { "title": title, "title_url": f"{document_name}.html#{version_node.get('ids')[0]}", "children": children, - "url": f"{document_name}.html#{whats_new_nodes[0]['ids'][0]}", + "url": f"{document_name}.html#{whatsnew_nodes[0]['ids'][0]}", } - whats_new_content.append(contents) + whatsnew.append(contents) - app.env.whatsnew_content = whats_new_content + app.env.whatsnew = whatsnew def add_whatsnew(app, pagename, templatename, context, doctree): @@ -606,7 +605,7 @@ def add_whatsnew(app, pagename, templatename, context, doctree): return whatsnew = context.get("whatsnew", []) - whatsnew.extend(app.env.whatsnew_content) + whatsnew.extend(app.env.whatsnew) context["whatsnew"] = whatsnew sidebar = context.get("sidebars", []) sidebar.append("whatsnew_sidebar.html") From c01c80df13f49ffd8a0a839160aec28141229329 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Wed, 11 Dec 2024 17:49:06 +0100 Subject: [PATCH 30/73] feat: update the template --- .../templates/changelog_template.jinja | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/ansys_sphinx_theme/templates/changelog_template.jinja b/src/ansys_sphinx_theme/templates/changelog_template.jinja index 73d01f600..f50c9cd03 100644 --- a/src/ansys_sphinx_theme/templates/changelog_template.jinja +++ b/src/ansys_sphinx_theme/templates/changelog_template.jinja @@ -1,3 +1,15 @@ +{% set minor_version = ".".join(versiondata["version"].split(".")[0:2]) %} +{% set title_format = "Version "+ minor_version %} +{% if render_title %} +{% if versiondata.name %} +`{{ title_format }} <{{ versiondata.name }}/release/v{{ versiondata.version }}>`- ({{ versiondata.date }}) +{{ top_underline * ((versiondata.name + versiondata.version + versiondata.version + versiondata.date)|length + 40)}} +{% else %} +{{ title_format }} ({{ versiondata.date }}) +{{ top_underline * ((versiondata.version + versiondata.date)|length + 40)}} +{% endif %} +{% endif %} + {% if sections["Whatsnew"] %} {%+ for category, val in sections["Whatsnew"].items() +%} {%+ if definitions.get(category) and definitions[category].get('name') +%} @@ -6,12 +18,22 @@ {% endif %} {%- for text, values in sections["Whatsnew"][category].items() %} -{{ text }} + {{ text }} {% endfor -%} {% endfor %} {% endif %} +{% if render_title %} +{% if versiondata.name %} +`{{versiondata.version}} <{{ versiondata.name }}/release/v{{ versiondata.version }}>`- ({{ versiondata.date }}) +{{ top_underline * ((versiondata.name + versiondata.version + versiondata.version + versiondata.date)|length + 20)}} +{% else %} +{{versiondata.version}} ({{ versiondata.date }}) +{{ top_underline * ((versiondata.version + versiondata.date)|length + 3)}} +{% endif %} +{% endif %} + {% if sections[""] %} Changelog From 5bb7efa6594f3644596e7f2a9193cfc87cdd203b Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:27:09 -0500 Subject: [PATCH 31/73] only change changelog format in template & parse docs in __init__ file --- pyproject.toml | 2 +- src/ansys_sphinx_theme/__init__.py | 97 +++++++++++++++++-- .../templates/changelog_template.jinja | 39 -------- 3 files changed, 90 insertions(+), 48 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index eececff69..ace72e21b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -124,7 +124,7 @@ directory = "doc/changelog.d" filename = "doc/source/changelog.rst" template = "ansys_sphinx_theme:changelog_template.jinja" start_string = ".. towncrier release notes start\n" -title_format = "Version `{version} `_ ({project_date})" +title_format = "`{version} `_ ({project_date})" issue_format = "`#{issue} `_" all_bullets = false underlines = ["=", "^"] diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 6f23dd9eb..41f20e27c 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -25,6 +25,7 @@ import logging import os import pathlib +import re import subprocess from typing import Any, Dict @@ -65,6 +66,15 @@ ANSYS_LOGO_LINK = "https://www.ansys.com/" PYANSYS_LOGO_LINK = "https://docs.pyansys.com/" +"""Semantic version regex as found on semver.org: +https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string""" +SEMVER_REGEX = ( + r"(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)" + r"(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)" + r"(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?" + r"(?:\+(>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?" +) + # make logo paths available ansys_favicon = str((LOGOS_PATH / "ansys-favicon.png").absolute()) ansys_logo_black = str((LOGOS_PATH / "ansys_logo_black_cropped.jpg").absolute()) @@ -538,16 +548,86 @@ def check_for_depreciated_theme_options(app: Sphinx): ) -def extract_whatsnew(app, doctree, docname): - """Extract the what's new content from the document.""" +def retrieve_whatsnew_input(app: Sphinx): config_options = app.config.html_theme_options whats_new_options = config_options.get("whatsnew") if not whats_new_options: return + no_of_contents = whats_new_options.get("no_of_headers", 3) - document_name = whats_new_options.get("file", "release-note") - doctree = app.env.get_doctree(document_name) + whatsnew_file = whats_new_options.get("whatsnew_file", "whatsnew") # .yml + changelog_file = whats_new_options.get("changelog_file", "changelog") # .rst + + return no_of_contents, whatsnew_file, changelog_file + + +def add_whatsnew_changelog(app, doctree, docname): + """Add what's new content from whatsnew.yml into the changelog.rst file.""" + no_of_contents, whatsnew_file, changelog_file = retrieve_whatsnew_input(app) + + # Add what's new content to changelog.rst file + # print("Adding what's new content to changelog.rst file") + + if changelog_file in docname: + # Read changelog.rst file + # Extract the what's new content from the changelog file + doctree = app.env.get_doctree(changelog_file) + whatsnew = [] + docs_content = doctree.traverse(nodes.section) + app.env.whatsnew = [] + + doctree = app.env.get_doctree(docname) + print(f"HELLOOO\n{docname}\n") + # print(docname) + # print(doctree) + + docs_content = doctree.traverse(nodes.section) + # print("DOCS CONTENT") + # print(docs_content) + + if not docs_content: + # print(f"NO CONTENTS\n") + return + + for section in doctree.traverse(nodes.section): + title = section.next_node(nodes.Titular) + if title: + print(title.astext()) + # minor_versions = [] + minor_versions = {} + for node in docs_content: + section_name = node.get("names") + if section_name: + patch_version = re.search(SEMVER_REGEX, section_name[0]) + if patch_version: + minor_version = ".".join(patch_version.groups()[:2]) + if minor_version not in minor_versions: + # create section for minor version + minor_version_section = nodes.section( + ids=[f"version-{minor_version}"], names=[f"Version {minor_version}"] + ) + minor_version_section += nodes.title("", f"Version {minor_version}") + # minor_version_section.setup_child(node) + minor_versions[minor_version] = [ + minor_version_section, + node.parent, + node.children, + ] + doctree.insert(0, minor_version_section) + + # print(f"MINOR VERSIONS\n{minor_versions}\n") + print(doctree) + + app.env.whatsnew = doctree + + +def extract_whatsnew(app, doctree, docname): + """Extract the what's new content from the document.""" + no_of_contents, whatsnew_file, changelog_file = retrieve_whatsnew_input(app) + + # Extract the what's new content from the changelog file + doctree = app.env.get_doctree(changelog_file) whatsnew = [] docs_content = doctree.traverse(nodes.section) app.env.whatsnew = [] @@ -583,9 +663,9 @@ def extract_whatsnew(app, doctree, docname): contents = { "title": title, - "title_url": f"{document_name}.html#{version_node.get('ids')[0]}", + "title_url": f"{changelog_file}.html#{version_node.get('ids')[0]}", "children": children, - "url": f"{document_name}.html#{whatsnew_nodes[0]['ids'][0]}", + "url": f"{changelog_file}.html#{whatsnew_nodes[0]['ids'][0]}", } whatsnew.append(contents) @@ -593,7 +673,7 @@ def extract_whatsnew(app, doctree, docname): app.env.whatsnew = whatsnew -def add_whatsnew(app, pagename, templatename, context, doctree): +def add_whatsnew_sidebar(app, pagename, templatename, context, doctree): """Add what's new section to the context.""" config_options = app.config.html_theme_options whats_new_options = config_options.get("whatsnew") @@ -648,8 +728,9 @@ def setup(app: Sphinx) -> Dict: app.connect("builder-inited", configure_theme_logo) app.connect("builder-inited", build_quarto_cheatsheet) app.connect("builder-inited", check_for_depreciated_theme_options) + app.connect("doctree-resolved", add_whatsnew_changelog) app.connect("doctree-resolved", extract_whatsnew) - app.connect("html-page-context", add_whatsnew) + app.connect("html-page-context", add_whatsnew_sidebar) app.connect("html-page-context", update_footer_theme) app.connect("html-page-context", fix_edit_html_page_context) app.connect("html-page-context", add_cheat_sheet) diff --git a/src/ansys_sphinx_theme/templates/changelog_template.jinja b/src/ansys_sphinx_theme/templates/changelog_template.jinja index f50c9cd03..b6389c14f 100644 --- a/src/ansys_sphinx_theme/templates/changelog_template.jinja +++ b/src/ansys_sphinx_theme/templates/changelog_template.jinja @@ -1,44 +1,5 @@ -{% set minor_version = ".".join(versiondata["version"].split(".")[0:2]) %} -{% set title_format = "Version "+ minor_version %} -{% if render_title %} -{% if versiondata.name %} -`{{ title_format }} <{{ versiondata.name }}/release/v{{ versiondata.version }}>`- ({{ versiondata.date }}) -{{ top_underline * ((versiondata.name + versiondata.version + versiondata.version + versiondata.date)|length + 40)}} -{% else %} -{{ title_format }} ({{ versiondata.date }}) -{{ top_underline * ((versiondata.version + versiondata.date)|length + 40)}} -{% endif %} -{% endif %} - -{% if sections["Whatsnew"] %} - {%+ for category, val in sections["Whatsnew"].items() +%} - {%+ if definitions.get(category) and definitions[category].get('name') +%} -{{ definitions[category]['name'] }} -{% set underline = underlines[0] if underlines else '^' %}{{ underline * definitions[category]['name']|length }} - {% endif %} - {%- for text, values in sections["Whatsnew"][category].items() %} - - {{ text }} - - {% endfor -%} - {% endfor %} -{% endif %} - -{% if render_title %} -{% if versiondata.name %} -`{{versiondata.version}} <{{ versiondata.name }}/release/v{{ versiondata.version }}>`- ({{ versiondata.date }}) -{{ top_underline * ((versiondata.name + versiondata.version + versiondata.version + versiondata.date)|length + 20)}} -{% else %} -{{versiondata.version}} ({{ versiondata.date }}) -{{ top_underline * ((versiondata.version + versiondata.date)|length + 3)}} -{% endif %} -{% endif %} - {% if sections[""] %} -Changelog -{% set underline = underlines[0] if underlines else '^' %}{{ underline * 9 }} - .. tab-set:: {%+ for category, val in definitions.items() if category in sections[""] +%} .. tab-item:: {{ definitions[category]['name'] }} From 3398094584556ab7e251d5df55bc4a10515be71e Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:21:25 -0500 Subject: [PATCH 32/73] clean up code --- src/ansys_sphinx_theme/__init__.py | 40 +++++++----------------------- 1 file changed, 9 insertions(+), 31 deletions(-) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 41f20e27c..8855a9278 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -566,60 +566,37 @@ def add_whatsnew_changelog(app, doctree, docname): """Add what's new content from whatsnew.yml into the changelog.rst file.""" no_of_contents, whatsnew_file, changelog_file = retrieve_whatsnew_input(app) - # Add what's new content to changelog.rst file - # print("Adding what's new content to changelog.rst file") - if changelog_file in docname: # Read changelog.rst file # Extract the what's new content from the changelog file - doctree = app.env.get_doctree(changelog_file) - whatsnew = [] - docs_content = doctree.traverse(nodes.section) - app.env.whatsnew = [] - doctree = app.env.get_doctree(docname) - print(f"HELLOOO\n{docname}\n") - # print(docname) - # print(doctree) - docs_content = doctree.traverse(nodes.section) # print("DOCS CONTENT") # print(docs_content) if not docs_content: - # print(f"NO CONTENTS\n") return - for section in doctree.traverse(nodes.section): - title = section.next_node(nodes.Titular) - if title: - print(title.astext()) - # minor_versions = [] - minor_versions = {} + minor_versions = [] for node in docs_content: + # remove one node and add another node - not doctree section_name = node.get("names") if section_name: patch_version = re.search(SEMVER_REGEX, section_name[0]) if patch_version: minor_version = ".".join(patch_version.groups()[:2]) if minor_version not in minor_versions: - # create section for minor version + minor_versions.append(minor_version) minor_version_section = nodes.section( ids=[f"version-{minor_version}"], names=[f"Version {minor_version}"] ) minor_version_section += nodes.title("", f"Version {minor_version}") - # minor_version_section.setup_child(node) - minor_versions[minor_version] = [ - minor_version_section, - node.parent, - node.children, - ] - doctree.insert(0, minor_version_section) - - # print(f"MINOR VERSIONS\n{minor_versions}\n") - print(doctree) + # print(f"node: {node}") + node.extend(minor_version_section) + print("") - app.env.whatsnew = doctree + # print(app.env) + # doctree = app.env.get_doctree(docname) def extract_whatsnew(app, doctree, docname): @@ -728,6 +705,7 @@ def setup(app: Sphinx) -> Dict: app.connect("builder-inited", configure_theme_logo) app.connect("builder-inited", build_quarto_cheatsheet) app.connect("builder-inited", check_for_depreciated_theme_options) + # env-updated or doctree-resolved (after doctree-read and before html-page-context) app.connect("doctree-resolved", add_whatsnew_changelog) app.connect("doctree-resolved", extract_whatsnew) app.connect("html-page-context", add_whatsnew_sidebar) From 0bb5cd3f05b07cb3e0e778a0c818d020cb84aa87 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 17 Dec 2024 08:37:18 -0500 Subject: [PATCH 33/73] add whatsnew.yml --- doc/changelog.d/whatsnew.yml | 66 ++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 doc/changelog.d/whatsnew.yml diff --git a/doc/changelog.d/whatsnew.yml b/doc/changelog.d/whatsnew.yml new file mode 100644 index 000000000..20d649753 --- /dev/null +++ b/doc/changelog.d/whatsnew.yml @@ -0,0 +1,66 @@ +fragments: +- title: Launch GUI + patch: 0.6.1 + content: | + Open the current project with Mechanical GUI. + + .. code:: python + + from ansys.mechanical.core import App + + app = App() + app.save() + app.launch_gui() + + Above code opens up the temporarily saved ``.mechdb`` or ``.mechdat`` files. + The files are deleted when GUI is closed . For more info check + `launch_gui() <../api/ansys/mechanical/core/embedding/launch_gui/index.html>`_ function + + Opens up the specified project file. + + .. code:: python + + launch_gui("path/to/project.mechdb") + +- title: Print Mechanical tree + patch: 0.6.0 + content: | + This feature let you see the heirachial Mechanical project tree. + It also shows whether an object is suppressed or not. + + .. code:: python + + import ansys.mechanical.core as mech + + app = mech.App() + app.update_globals(globals()) + app.print_tree() + + .. code:: shell + + ... ├── Project + ... | ├── Model + ... | | ├── Geometry Imports + ... | | ├── Geometry + ... | | ├── Materials + ... | | ├── Coordinate Systems + ... | | | ├── Global Coordinate System + ... | | ├── Remote Points + ... | | ├── Mesh + +- title: Visualize geometry in 3D + patch: 0.5.9 + content: | + Visualize imported geometry in 3D. This feature is available only from 24R1 or later. + + .. code:: python + + import ansys.mechanical.core as mech + + app = mech.App(version=242) + app.update_globals(globals()) + + # Import the geometry + + # visualize + app.plot() \ No newline at end of file From a49227289c2d3eeecd0ecf024e27e404ff438f45 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Tue, 17 Dec 2024 17:49:06 +0100 Subject: [PATCH 34/73] fix: add the doctree read --- src/ansys_sphinx_theme/__init__.py | 59 +++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 8855a9278..94c2b42cc 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -565,6 +565,10 @@ def retrieve_whatsnew_input(app: Sphinx): def add_whatsnew_changelog(app, doctree, docname): """Add what's new content from whatsnew.yml into the changelog.rst file.""" no_of_contents, whatsnew_file, changelog_file = retrieve_whatsnew_input(app) + + if not changelog_file in docname: + return + if changelog_file in docname: # Read changelog.rst file @@ -572,7 +576,6 @@ def add_whatsnew_changelog(app, doctree, docname): doctree = app.env.get_doctree(docname) docs_content = doctree.traverse(nodes.section) # print("DOCS CONTENT") - # print(docs_content) if not docs_content: return @@ -667,7 +670,58 @@ def add_whatsnew_sidebar(app, pagename, templatename, context, doctree): sidebar = context.get("sidebars", []) sidebar.append("whatsnew_sidebar.html") context["sidebars"] = sidebar - + +def get_whatsnew_doctree(app, doctree): + + sections = doctree.traverse(nodes.document) + if not sections: + return + + src_files = app.env.srcdir + changelog_file = pathlib.Path(src_files) / "changelog.rst" + changelog_doctree_sections = [section for section in sections if section.get("source") == str(changelog_file)] + print(changelog_doctree_sections) + + # check minor and patch version + complete_version = "1.2.3" + # TODO : get the version from the config, alo get patch and minor version + minor_version = get_version_match(app.env.config.version) + patch_version = app.env.config.version.split(".")[2] + + if patch_version == "0": + # create a title for the all the minor versions + # add another title of whatsnew + return + + elif patch_version == "dev0": + return + # check if the minor version exists + # add whatnew of patch to the whatsnew of minor + + # get the doctree + + # get the doctree + no_of_contents, whatsnew_file, changelog_file = retrieve_whatsnew_input(app) + + + # get the sections of patch + + # no need of patch version nodes + + # create a new node with title of minor version and sub title whatsnew + # add the node to the doctree before patch version node + + minor_version_node = nodes.section(ids=[f"version-{minor_version}"], names=[f"Version {minor_version}"]) + minor_version_node += nodes.title("", f"Version {minor_version}") + minor_version_node += nodes.title("", "Whats New") + minor_version_node += nodes.paragraph("", "Add the whatsnew content here") + + # add the node to the doctree + for node in changelog_doctree_sections: + node.next_node(minor_version_node) + + doctree.extend(minor_version_node) + def setup(app: Sphinx) -> Dict: """Connect to the Sphinx theme app. @@ -706,6 +760,7 @@ def setup(app: Sphinx) -> Dict: app.connect("builder-inited", build_quarto_cheatsheet) app.connect("builder-inited", check_for_depreciated_theme_options) # env-updated or doctree-resolved (after doctree-read and before html-page-context) + app.connect("doctree-read", get_whatsnew_doctree) app.connect("doctree-resolved", add_whatsnew_changelog) app.connect("doctree-resolved", extract_whatsnew) app.connect("html-page-context", add_whatsnew_sidebar) From 33238687d6f97ffa5c51c52a606905955714c844 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 17 Dec 2024 16:52:13 -0500 Subject: [PATCH 35/73] add minor version section titles --- src/ansys_sphinx_theme/__init__.py | 148 +++++++++++++++++------------ 1 file changed, 86 insertions(+), 62 deletions(-) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 94c2b42cc..eb437f756 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -562,44 +562,65 @@ def retrieve_whatsnew_input(app: Sphinx): return no_of_contents, whatsnew_file, changelog_file -def add_whatsnew_changelog(app, doctree, docname): - """Add what's new content from whatsnew.yml into the changelog.rst file.""" - no_of_contents, whatsnew_file, changelog_file = retrieve_whatsnew_input(app) - - if not changelog_file in docname: +def add_whatsnew_changelog(app, doctree): + """Create doctree with minor version and what's new content.""" + # Read the file and get the sections from the file as a list. For example, + # sections = [
      ] + sections = doctree.traverse(nodes.document) + if not sections: return + # The source directory of the documentation: {repository_root}/doc/source + src_files = app.env.srcdir + changelog_file = pathlib.Path(src_files) / "changelog.rst" - if changelog_file in docname: - # Read changelog.rst file - # Extract the what's new content from the changelog file - doctree = app.env.get_doctree(docname) - docs_content = doctree.traverse(nodes.section) - # print("DOCS CONTENT") - - if not docs_content: - return - - minor_versions = [] - for node in docs_content: - # remove one node and add another node - not doctree - section_name = node.get("names") - if section_name: - patch_version = re.search(SEMVER_REGEX, section_name[0]) - if patch_version: - minor_version = ".".join(patch_version.groups()[:2]) - if minor_version not in minor_versions: - minor_versions.append(minor_version) - minor_version_section = nodes.section( - ids=[f"version-{minor_version}"], names=[f"Version {minor_version}"] - ) - minor_version_section += nodes.title("", f"Version {minor_version}") - # print(f"node: {node}") - node.extend(minor_version_section) - print("") + # Get the file name of the section using section.get("source") and return the section + # if section.get("source") is equal to the changelog_file + changelog_doctree_sections = [ + section for section in sections if section.get("source") == str(changelog_file) + ] + + # Return if the changelog file sections are not found + if not changelog_doctree_sections: + return - # print(app.env) - # doctree = app.env.get_doctree(docname) + # to do: get the version from the config, also get patch and minor version + minor_version = get_version_match(app.env.config.version) + patch_version = app.env.config.version.split(".")[2] + + docs_content = doctree.traverse(nodes.section) + minor_versions = [] + # minor_versions = {} + for node in docs_content: + # Get the content of the next node + next_node = node.next_node(nodes.reference) + # Get the name of the next node + section_name = next_node.get("name") + if section_name: + # Get the patch version from the section name + patch_version = re.search(SEMVER_REGEX, section_name) + if patch_version: + # Create the minor version from the patch version + minor_version = ".".join(patch_version.groups()[:2]) + if minor_version not in minor_versions: + minor_versions.append(minor_version) + # Create a section for the minor version + minor_version_section = nodes.section( + ids=[f"version-{minor_version}"], names=[f"Version {minor_version}"] + ) + # Add the title to the section for the minor version + minor_version_section += nodes.title("", f"Version {minor_version}") + + if "release notes" in node[0].astext().lower(): + # Add the title with the minor version after "Release Notes" + node.insert(1, minor_version_section) + else: + # Add the title at the beginning of a section with a patch version + node.insert(0, minor_version_section) + + # minor_versions[minor_version] = minor_version_section + # print(node) + # print("\n\n") def extract_whatsnew(app, doctree, docname): @@ -670,58 +691,61 @@ def add_whatsnew_sidebar(app, pagename, templatename, context, doctree): sidebar = context.get("sidebars", []) sidebar.append("whatsnew_sidebar.html") context["sidebars"] = sidebar - + + def get_whatsnew_doctree(app, doctree): - sections = doctree.traverse(nodes.document) if not sections: return - + src_files = app.env.srcdir changelog_file = pathlib.Path(src_files) / "changelog.rst" - changelog_doctree_sections = [section for section in sections if section.get("source") == str(changelog_file)] + changelog_doctree_sections = [ + section for section in sections if section.get("source") == str(changelog_file) + ] print(changelog_doctree_sections) - + # check minor and patch version - complete_version = "1.2.3" - # TODO : get the version from the config, alo get patch and minor version - minor_version = get_version_match(app.env.config.version) + # complete_version = "1.2.3" + # to do: get the version from the config, also get patch and minor version + minor_version = get_version_match(app.env.config.version) patch_version = app.env.config.version.split(".")[2] - + if patch_version == "0": # create a title for the all the minor versions # add another title of whatsnew return - + elif patch_version == "dev0": return # check if the minor version exists - # add whatnew of patch to the whatsnew of minor - + # add whatnew of patch to the whatsnew of minor + # get the doctree - + # get the doctree no_of_contents, whatsnew_file, changelog_file = retrieve_whatsnew_input(app) - - - # get the sections of patch - + + # get the sections of patch + # no need of patch version nodes - - # create a new node with title of minor version and sub title whatsnew - # add the node to the doctree before patch version node - - minor_version_node = nodes.section(ids=[f"version-{minor_version}"], names=[f"Version {minor_version}"]) + + # create a new node with title of minor version and sub title whatsnew + # add the node to the doctree before patch version node + + minor_version_node = nodes.section( + ids=[f"version-{minor_version}"], names=[f"Version {minor_version}"] + ) minor_version_node += nodes.title("", f"Version {minor_version}") - minor_version_node += nodes.title("", "Whats New") + minor_version_node += nodes.title("", "What's New") minor_version_node += nodes.paragraph("", "Add the whatsnew content here") - + # add the node to the doctree for node in changelog_doctree_sections: node.next_node(minor_version_node) - + doctree.extend(minor_version_node) - + def setup(app: Sphinx) -> Dict: """Connect to the Sphinx theme app. @@ -760,8 +784,8 @@ def setup(app: Sphinx) -> Dict: app.connect("builder-inited", build_quarto_cheatsheet) app.connect("builder-inited", check_for_depreciated_theme_options) # env-updated or doctree-resolved (after doctree-read and before html-page-context) - app.connect("doctree-read", get_whatsnew_doctree) - app.connect("doctree-resolved", add_whatsnew_changelog) + # app.connect("doctree-read", get_whatsnew_doctree) + app.connect("doctree-read", add_whatsnew_changelog) app.connect("doctree-resolved", extract_whatsnew) app.connect("html-page-context", add_whatsnew_sidebar) app.connect("html-page-context", update_footer_theme) From cb62c4a27e33efa4ed2902054ea6ec34336c6416 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 17 Dec 2024 17:35:36 -0500 Subject: [PATCH 36/73] add what's new sections under corresponding minor versions --- doc/{changelog.d => source}/whatsnew.yml | 6 +-- src/ansys_sphinx_theme/__init__.py | 51 ++++++++++++++++++++---- 2 files changed, 46 insertions(+), 11 deletions(-) rename doc/{changelog.d => source}/whatsnew.yml (97%) diff --git a/doc/changelog.d/whatsnew.yml b/doc/source/whatsnew.yml similarity index 97% rename from doc/changelog.d/whatsnew.yml rename to doc/source/whatsnew.yml index 20d649753..ade414cb2 100644 --- a/doc/changelog.d/whatsnew.yml +++ b/doc/source/whatsnew.yml @@ -1,6 +1,6 @@ fragments: - title: Launch GUI - patch: 0.6.1 + patch: 1.2.1 content: | Open the current project with Mechanical GUI. @@ -23,7 +23,7 @@ fragments: launch_gui("path/to/project.mechdb") - title: Print Mechanical tree - patch: 0.6.0 + patch: 0.16.6 content: | This feature let you see the heirachial Mechanical project tree. It also shows whether an object is suppressed or not. @@ -49,7 +49,7 @@ fragments: ... | | ├── Mesh - title: Visualize geometry in 3D - patch: 0.5.9 + patch: 0.16.3 content: | Visualize imported geometry in 3D. This feature is available only from 24R1 or later. diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index eb437f756..5e7fe907e 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -32,6 +32,7 @@ from docutils import nodes from sphinx import addnodes from sphinx.application import Sphinx +import yaml from ansys_sphinx_theme.extension.linkcode import DOMAIN_KEYS, sphinx_linkcode_resolve from ansys_sphinx_theme.latex import generate_404 @@ -564,6 +565,7 @@ def retrieve_whatsnew_input(app: Sphinx): def add_whatsnew_changelog(app, doctree): """Create doctree with minor version and what's new content.""" + no_of_contents, whatsnew_file, changelog_file = retrieve_whatsnew_input(app) # Read the file and get the sections from the file as a list. For example, # sections = [
      ] sections = doctree.traverse(nodes.document) @@ -572,7 +574,7 @@ def add_whatsnew_changelog(app, doctree): # The source directory of the documentation: {repository_root}/doc/source src_files = app.env.srcdir - changelog_file = pathlib.Path(src_files) / "changelog.rst" + changelog_file = pathlib.Path(src_files) / f"{changelog_file}.rst" # Get the file name of the section using section.get("source") and return the section # if section.get("source") is equal to the changelog_file @@ -584,13 +586,23 @@ def add_whatsnew_changelog(app, doctree): if not changelog_doctree_sections: return + # Open what's new yaml file, load the data, and get the minor versions + whatsnew_file = pathlib.Path(src_files) / f"{whatsnew_file}.yml" + if whatsnew_file.exists(): + with pathlib.Path.open(whatsnew_file, "r", encoding="utf-8") as file: + whatsnew_data = yaml.safe_load(file) + + whatsnew_minor_versions = set() + for fragment in whatsnew_data["fragments"]: + yaml_minor_version = ".".join(fragment["patch"].split(".")[:2]) + whatsnew_minor_versions.add(yaml_minor_version) + # to do: get the version from the config, also get patch and minor version minor_version = get_version_match(app.env.config.version) patch_version = app.env.config.version.split(".")[2] + existing_minor_versions = [] docs_content = doctree.traverse(nodes.section) - minor_versions = [] - # minor_versions = {} for node in docs_content: # Get the content of the next node next_node = node.next_node(nodes.reference) @@ -602,8 +614,10 @@ def add_whatsnew_changelog(app, doctree): if patch_version: # Create the minor version from the patch version minor_version = ".".join(patch_version.groups()[:2]) - if minor_version not in minor_versions: - minor_versions.append(minor_version) + if minor_version not in existing_minor_versions: + # Add minor version to list of existing minor versions + existing_minor_versions.append(minor_version) + # Create a section for the minor version minor_version_section = nodes.section( ids=[f"version-{minor_version}"], names=[f"Version {minor_version}"] @@ -611,6 +625,15 @@ def add_whatsnew_changelog(app, doctree): # Add the title to the section for the minor version minor_version_section += nodes.title("", f"Version {minor_version}") + # Add "What's New" section under the minor version if the minor version is in + # the what's new data + if whatsnew_file.exists() and (minor_version in whatsnew_minor_versions): + minor_version_whatsnew = add_whatsnew_to_minor_version( + minor_version, whatsnew_data + ) + minor_version_section.extend(minor_version_whatsnew) + + # Insert the minor_version_section into the node if "release notes" in node[0].astext().lower(): # Add the title with the minor version after "Release Notes" node.insert(1, minor_version_section) @@ -618,9 +641,21 @@ def add_whatsnew_changelog(app, doctree): # Add the title at the beginning of a section with a patch version node.insert(0, minor_version_section) - # minor_versions[minor_version] = minor_version_section - # print(node) - # print("\n\n") + +def add_whatsnew_to_minor_version(minor_version, whatsnew_data): + """Add the what's new title and content under the minor version.""" + # Add the what's new section and title + minor_version_whatsnew = nodes.section( + ids=[f"version-{minor_version}-whatsnew"], names=["What's New"] + ) + minor_version_whatsnew += nodes.title("", "What's New") + + # For each fragment in the what's new yaml file, add the content as a paragraph + for fragment in whatsnew_data["fragments"]: + if minor_version in fragment["patch"]: + minor_version_whatsnew += nodes.paragraph("", fragment["content"]) + + return minor_version_whatsnew def extract_whatsnew(app, doctree, docname): From e40315bf23b795b0a5188ad5fb121613b29f4572 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Thu, 19 Dec 2024 15:20:17 -0500 Subject: [PATCH 37/73] add dropdowns to whatsnew sections --- src/ansys_sphinx_theme/__init__.py | 115 ++++++++++++++--------------- 1 file changed, 55 insertions(+), 60 deletions(-) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 5e7fe907e..57e043749 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -186,6 +186,50 @@ def setup_default_html_theme_options(app): theme_options["pygments_dark_style"] = "monokai" +def fix_toctree(app: Sphinx, pagename: str, templatename: str, context: Dict[str, Any], doctree: nodes.document): + """Add the what's new content to the html page.""" + from bs4 import BeautifulSoup + + if "changelog" in pagename: + body = context.get("body", "") + toc = context.get("toc", "") + + print(toc) + + # add minor versions and what's new sections to toctree + + # body = BeautifulSoup(body, 'html.parser') + # # print(soup.prettify()) + # for section in body.find_all('section'): + # # release_notes_title = section.find('h1') + # # print(release_notes_title) + # for h2 in section.find_all('h2'): + # patch_version = re.search(SEMVER_REGEX, h2.text) + # if patch_version: + # # Create the minor version from the patch version + # minor_version = ".".join(patch_version.groups()[:2]) + # if minor_version not in minor_versions: + # minor_versions.append(minor_version) + # minor_version = ".".join(patch_version.groups()[:2]) + + # h2.name = "h3" + + # minor_version_title = body.new_tag("h2", id=f"version-{minor_version}") + # minor_version_title.string = f"Version {minor_version}" + + # # if release_notes_title != None: + # # release_notes_title.append(minor_version_title) + # # else: + # h2.parent.append(minor_version_title) + # # print(h2.parent) + # # print(h2) + # # print("") + # else: + # h2.name = "h3" + + # context["body"] = body + + def fix_edit_html_page_context( app: Sphinx, pagename: str, templatename: str, context: dict, doctree: nodes.document ) -> None: @@ -584,7 +628,7 @@ def add_whatsnew_changelog(app, doctree): # Return if the changelog file sections are not found if not changelog_doctree_sections: - return + return # Open what's new yaml file, load the data, and get the minor versions whatsnew_file = pathlib.Path(src_files) / f"{whatsnew_file}.yml" @@ -631,7 +675,7 @@ def add_whatsnew_changelog(app, doctree): minor_version_whatsnew = add_whatsnew_to_minor_version( minor_version, whatsnew_data ) - minor_version_section.extend(minor_version_whatsnew) + minor_version_section.append(minor_version_whatsnew) # Insert the minor_version_section into the node if "release notes" in node[0].astext().lower(): @@ -644,7 +688,7 @@ def add_whatsnew_changelog(app, doctree): def add_whatsnew_to_minor_version(minor_version, whatsnew_data): """Add the what's new title and content under the minor version.""" - # Add the what's new section and title + # Add the what's new section and title minor_version_whatsnew = nodes.section( ids=[f"version-{minor_version}-whatsnew"], names=["What's New"] ) @@ -653,7 +697,13 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): # For each fragment in the what's new yaml file, add the content as a paragraph for fragment in whatsnew_data["fragments"]: if minor_version in fragment["patch"]: - minor_version_whatsnew += nodes.paragraph("", fragment["content"]) + whatsnew_dropdown = nodes.container(body_classes=[""], chevron=True, container_classes=["sd-mb-3 sd-fade-in-slide-down"], design_component="dropdown", has_title=True, icon="", is_div=True, opened=False, title_classes=[""], type="dropdown") + whatsnew_dropdown += nodes.rubric("span", fragment["title"]) + whatsnew_dropdown += nodes.paragraph("xml:space='preserve'", fragment["content"]) + # lines = fragment["content"].split("\n") + # for line in lines: + # minor_version_whatsnew += nodes.literal_block("", line) + minor_version_whatsnew.append(whatsnew_dropdown) return minor_version_whatsnew @@ -728,60 +778,6 @@ def add_whatsnew_sidebar(app, pagename, templatename, context, doctree): context["sidebars"] = sidebar -def get_whatsnew_doctree(app, doctree): - sections = doctree.traverse(nodes.document) - if not sections: - return - - src_files = app.env.srcdir - changelog_file = pathlib.Path(src_files) / "changelog.rst" - changelog_doctree_sections = [ - section for section in sections if section.get("source") == str(changelog_file) - ] - print(changelog_doctree_sections) - - # check minor and patch version - # complete_version = "1.2.3" - # to do: get the version from the config, also get patch and minor version - minor_version = get_version_match(app.env.config.version) - patch_version = app.env.config.version.split(".")[2] - - if patch_version == "0": - # create a title for the all the minor versions - # add another title of whatsnew - return - - elif patch_version == "dev0": - return - # check if the minor version exists - # add whatnew of patch to the whatsnew of minor - - # get the doctree - - # get the doctree - no_of_contents, whatsnew_file, changelog_file = retrieve_whatsnew_input(app) - - # get the sections of patch - - # no need of patch version nodes - - # create a new node with title of minor version and sub title whatsnew - # add the node to the doctree before patch version node - - minor_version_node = nodes.section( - ids=[f"version-{minor_version}"], names=[f"Version {minor_version}"] - ) - minor_version_node += nodes.title("", f"Version {minor_version}") - minor_version_node += nodes.title("", "What's New") - minor_version_node += nodes.paragraph("", "Add the whatsnew content here") - - # add the node to the doctree - for node in changelog_doctree_sections: - node.next_node(minor_version_node) - - doctree.extend(minor_version_node) - - def setup(app: Sphinx) -> Dict: """Connect to the Sphinx theme app. @@ -818,13 +814,12 @@ def setup(app: Sphinx) -> Dict: app.connect("builder-inited", configure_theme_logo) app.connect("builder-inited", build_quarto_cheatsheet) app.connect("builder-inited", check_for_depreciated_theme_options) - # env-updated or doctree-resolved (after doctree-read and before html-page-context) - # app.connect("doctree-read", get_whatsnew_doctree) app.connect("doctree-read", add_whatsnew_changelog) app.connect("doctree-resolved", extract_whatsnew) app.connect("html-page-context", add_whatsnew_sidebar) app.connect("html-page-context", update_footer_theme) app.connect("html-page-context", fix_edit_html_page_context) + # app.connect("html-page-context", fix_toctree) app.connect("html-page-context", add_cheat_sheet) app.connect("build-finished", replace_html_tag) app.connect("build-finished", create_search_index) From 819adcdcaf889d078e06e0d08404f6a09fba4b7d Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Fri, 20 Dec 2024 12:13:54 -0500 Subject: [PATCH 38/73] literal block testing --- src/ansys_sphinx_theme/__init__.py | 60 +++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 57e043749..ae1b71dc8 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -186,17 +186,18 @@ def setup_default_html_theme_options(app): theme_options["pygments_dark_style"] = "monokai" -def fix_toctree(app: Sphinx, pagename: str, templatename: str, context: Dict[str, Any], doctree: nodes.document): +def fix_toctree( + app: Sphinx, pagename: str, templatename: str, context: Dict[str, Any], doctree: nodes.document +): """Add the what's new content to the html page.""" from bs4 import BeautifulSoup if "changelog" in pagename: body = context.get("body", "") toc = context.get("toc", "") - + + # Update toctree with minor & what's new sections print(toc) - - # add minor versions and what's new sections to toctree # body = BeautifulSoup(body, 'html.parser') # # print(soup.prettify()) @@ -211,12 +212,12 @@ def fix_toctree(app: Sphinx, pagename: str, templatename: str, context: Dict[str # if minor_version not in minor_versions: # minor_versions.append(minor_version) # minor_version = ".".join(patch_version.groups()[:2]) - + # h2.name = "h3" # minor_version_title = body.new_tag("h2", id=f"version-{minor_version}") # minor_version_title.string = f"Version {minor_version}" - + # # if release_notes_title != None: # # release_notes_title.append(minor_version_title) # # else: @@ -628,7 +629,7 @@ def add_whatsnew_changelog(app, doctree): # Return if the changelog file sections are not found if not changelog_doctree_sections: - return + return # Open what's new yaml file, load the data, and get the minor versions whatsnew_file = pathlib.Path(src_files) / f"{whatsnew_file}.yml" @@ -685,26 +686,59 @@ def add_whatsnew_changelog(app, doctree): # Add the title at the beginning of a section with a patch version node.insert(0, minor_version_section) + # print(doctree) + def add_whatsnew_to_minor_version(minor_version, whatsnew_data): """Add the what's new title and content under the minor version.""" - # Add the what's new section and title + # Add the what's new section and title minor_version_whatsnew = nodes.section( ids=[f"version-{minor_version}-whatsnew"], names=["What's New"] ) minor_version_whatsnew += nodes.title("", "What's New") + # + # How do you report issues? + # Visualize imported geometry in 3D. This feature is available only from 24R1 or later. + # + # import ansys.mechanical.core as mech + # app = mech.App(version=242) + # app.update_globals(globals()) + # # Import the geometry + # # visualize + # app.plot() + # For each fragment in the what's new yaml file, add the content as a paragraph for fragment in whatsnew_data["fragments"]: if minor_version in fragment["patch"]: - whatsnew_dropdown = nodes.container(body_classes=[""], chevron=True, container_classes=["sd-mb-3 sd-fade-in-slide-down"], design_component="dropdown", has_title=True, icon="", is_div=True, opened=False, title_classes=[""], type="dropdown") - whatsnew_dropdown += nodes.rubric("span", fragment["title"]) - whatsnew_dropdown += nodes.paragraph("xml:space='preserve'", fragment["content"]) + whatsnew_dropdown = nodes.container( + body_classes=[""], + chevron=True, + container_classes=["sd-mb-3 sd-fade-in-slide-down"], + design_component="dropdown", + has_title=True, + icon="", + is_div=True, + opened=False, + title_classes=[""], + type="dropdown", + ) + whatsnew_dropdown += nodes.rubric("", fragment["title"]) + # lines = fragment["content"].split("\n") - # for line in lines: - # minor_version_whatsnew += nodes.literal_block("", line) + + whatsnew_dropdown += nodes.literal_block( + force="False", + highlight_args={"highlight-python notranslate"}, + language="python", + xml_space="preserve", + text="print('hello world')", + ) + minor_version_whatsnew.append(whatsnew_dropdown) + # print(minor_version_whatsnew) + return minor_version_whatsnew From ce304bb7563bfaa91170ac452458e1562cd4e509 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Mon, 6 Jan 2025 17:21:56 -0500 Subject: [PATCH 39/73] add code blocks to whatsnew dropdowns --- LICENSE | 2 +- src/ansys_sphinx_theme/__init__.py | 87 +++++++++++++++++++++++------- 2 files changed, 68 insertions(+), 21 deletions(-) diff --git a/LICENSE b/LICENSE index 6a949e7fd..4a8652561 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 - 2024 ANSYS, Inc. and/or its affiliates. +Copyright (c) 2021 - 2025 ANSYS, Inc. and/or its affiliates. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index ae1b71dc8..4ed871b97 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2021 - 2024 ANSYS, Inc. and/or its affiliates. +# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # # @@ -22,6 +22,7 @@ """Module for the Ansys Sphinx theme.""" +from itertools import tee import logging import os import pathlib @@ -193,7 +194,7 @@ def fix_toctree( from bs4 import BeautifulSoup if "changelog" in pagename: - body = context.get("body", "") + # body = context.get("body", "") toc = context.get("toc", "") # Update toctree with minor & what's new sections @@ -697,17 +698,6 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): ) minor_version_whatsnew += nodes.title("", "What's New") - # - # How do you report issues? - # Visualize imported geometry in 3D. This feature is available only from 24R1 or later. - # - # import ansys.mechanical.core as mech - # app = mech.App(version=242) - # app.update_globals(globals()) - # # Import the geometry - # # visualize - # app.plot() - # For each fragment in the what's new yaml file, add the content as a paragraph for fragment in whatsnew_data["fragments"]: if minor_version in fragment["patch"]: @@ -727,13 +717,59 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): # lines = fragment["content"].split("\n") - whatsnew_dropdown += nodes.literal_block( - force="False", - highlight_args={"highlight-python notranslate"}, - language="python", - xml_space="preserve", - text="print('hello world')", - ) + # whatsnew_dropdown += nodes.paragraph("sd-card-text", "test paragraph") + + # source_code = [block.astext() for block in doctree.traverse(nodes.literal_block) + # if 'code' in block.attributes['classes']] + + content_lines = fragment["content"].split("\n") + + content_iterator = iter(enumerate(content_lines)) + iterator_copy, content_iterator = tee(iter(enumerate(content_lines))) + + for line_index, line in content_iterator: + if ".. code" in line: + code_block = nodes.container(classes=["highlight-python notranslate"]) + highlight_container = nodes.container(classes=["highlight"]) + + # Create literal block with copy button + literal_block = nodes.literal_block( + classes=[ + "sd-button sd-button--icon sd-button--icon-only sd-button--icon-small" + ], + icon="copy", + label="Copy", + title="Copy", + ) + + next_line = next(content_iterator, None) + next(iterator_copy, None) + if next_line is not None: + while (next_line[1].startswith(" ")) or (next_line[1] == ""): + formatted_line = next_line[1].lstrip() + "\n" + literal_block += nodes.inline(text=formatted_line) + next_line = next(content_iterator, None) + next(iterator_copy, None) + if next_line is None: + break + + highlight_container += literal_block + + code_block += highlight_container + whatsnew_dropdown += code_block + + if next_line is not None: + # formatted_line = next_line[1].replace("\n", "") + whatsnew_dropdown += nodes.line("sd-card-text", next_line[1]) + else: + whatsnew_dropdown += nodes.line("sd-card-text", line) + # check = next(iterator_copy, None) + # if (check is not None) and (".. code" in check[1]): + # print(check[1]) + # if line != "": + # whatsnew_dropdown += nodes.paragraph("sd-card-text", line) + # else: + # whatsnew_dropdown += nodes.line("sd-card-text", line) minor_version_whatsnew.append(whatsnew_dropdown) @@ -742,6 +778,17 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): return minor_version_whatsnew +# def has_next(iterator): +# # Create a copy of the iterator +# iterator_copy, iterator = tee(iterator) +# try: +# # Try to get the next item from the copy +# next(iterator_copy) +# return True +# except StopIteration: +# return False + + def extract_whatsnew(app, doctree, docname): """Extract the what's new content from the document.""" no_of_contents, whatsnew_file, changelog_file = retrieve_whatsnew_input(app) From 34e4e57f469238816ccdf69705866a3b839dacb5 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 7 Jan 2025 12:33:52 -0500 Subject: [PATCH 40/73] create separate function for code block generation & fix loop --- doc/source/whatsnew.yml | 6 +- src/ansys_sphinx_theme/__init__.py | 91 ++++++++++++++---------------- 2 files changed, 45 insertions(+), 52 deletions(-) diff --git a/doc/source/whatsnew.yml b/doc/source/whatsnew.yml index ade414cb2..0857e70eb 100644 --- a/doc/source/whatsnew.yml +++ b/doc/source/whatsnew.yml @@ -1,6 +1,6 @@ fragments: - title: Launch GUI - patch: 1.2.1 + version: 1.2.1 content: | Open the current project with Mechanical GUI. @@ -23,7 +23,7 @@ fragments: launch_gui("path/to/project.mechdb") - title: Print Mechanical tree - patch: 0.16.6 + version: 0.16.6 content: | This feature let you see the heirachial Mechanical project tree. It also shows whether an object is suppressed or not. @@ -49,7 +49,7 @@ fragments: ... | | ├── Mesh - title: Visualize geometry in 3D - patch: 0.16.3 + version: 0.16.3 content: | Visualize imported geometry in 3D. This feature is available only from 24R1 or later. diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 4ed871b97..01c558c42 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -640,7 +640,7 @@ def add_whatsnew_changelog(app, doctree): whatsnew_minor_versions = set() for fragment in whatsnew_data["fragments"]: - yaml_minor_version = ".".join(fragment["patch"].split(".")[:2]) + yaml_minor_version = ".".join(fragment["version"].split(".")[:2]) whatsnew_minor_versions.add(yaml_minor_version) # to do: get the version from the config, also get patch and minor version @@ -700,7 +700,7 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): # For each fragment in the what's new yaml file, add the content as a paragraph for fragment in whatsnew_data["fragments"]: - if minor_version in fragment["patch"]: + if minor_version in fragment["version"]: whatsnew_dropdown = nodes.container( body_classes=[""], chevron=True, @@ -715,69 +715,62 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): ) whatsnew_dropdown += nodes.rubric("", fragment["title"]) - # lines = fragment["content"].split("\n") - - # whatsnew_dropdown += nodes.paragraph("sd-card-text", "test paragraph") - - # source_code = [block.astext() for block in doctree.traverse(nodes.literal_block) - # if 'code' in block.attributes['classes']] - + # Split content from YAML file into list content_lines = fragment["content"].split("\n") + # Create iterator for the content_lines content_iterator = iter(enumerate(content_lines)) iterator_copy, content_iterator = tee(iter(enumerate(content_lines))) for line_index, line in content_iterator: + next(iterator_copy, None) if ".. code" in line: - code_block = nodes.container(classes=["highlight-python notranslate"]) - highlight_container = nodes.container(classes=["highlight"]) - - # Create literal block with copy button - literal_block = nodes.literal_block( - classes=[ - "sd-button sd-button--icon sd-button--icon-only sd-button--icon-small" - ], - icon="copy", - label="Copy", - title="Copy", - ) - - next_line = next(content_iterator, None) - next(iterator_copy, None) - if next_line is not None: - while (next_line[1].startswith(" ")) or (next_line[1] == ""): - formatted_line = next_line[1].lstrip() + "\n" - literal_block += nodes.inline(text=formatted_line) - next_line = next(content_iterator, None) - next(iterator_copy, None) - if next_line is None: - break - - highlight_container += literal_block - - code_block += highlight_container + code_block = create_code_block(content_iterator, iterator_copy) whatsnew_dropdown += code_block - - if next_line is not None: - # formatted_line = next_line[1].replace("\n", "") - whatsnew_dropdown += nodes.line("sd-card-text", next_line[1]) else: whatsnew_dropdown += nodes.line("sd-card-text", line) - # check = next(iterator_copy, None) - # if (check is not None) and (".. code" in check[1]): - # print(check[1]) - # if line != "": - # whatsnew_dropdown += nodes.paragraph("sd-card-text", line) - # else: - # whatsnew_dropdown += nodes.line("sd-card-text", line) minor_version_whatsnew.append(whatsnew_dropdown) - # print(minor_version_whatsnew) - return minor_version_whatsnew +def create_code_block(content_iterator, iterator_copy): + code_block = nodes.container(classes=["highlight-python notranslate"]) + highlight_container = nodes.container(classes=["highlight"]) + + # Create literal block with copy button + literal_block = nodes.literal_block( + classes=["sd-button sd-button--icon sd-button--icon-only sd-button--icon-small"], + icon="copy", + label="Copy", + title="Copy", + ) + + next_line = next(content_iterator, None) + next_line_copy = next(iterator_copy, None) + + if next_line is not None: + while next_line[1].startswith(" ") or (next_line[1] == ""): + formatted_line = next_line[1].lstrip() + "\n" + literal_block += nodes.inline(text=formatted_line) + + next_line_copy = next(iterator_copy, None) + if next_line_copy is not None: + if next_line_copy[1].startswith(" ") or next_line_copy[1] == "": + next_line = next(content_iterator, None) + else: + break + else: + break + + highlight_container += literal_block + + code_block += highlight_container + + return code_block + + # def has_next(iterator): # # Create a copy of the iterator # iterator_copy, iterator = tee(iterator) From f603187c2989043cd3c33a01995a8a9140d3d6e8 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Fri, 10 Jan 2025 10:04:08 -0500 Subject: [PATCH 41/73] fix next(iterator) issue and rename function --- doc/source/whatsnew.yml | 10 +-- src/ansys_sphinx_theme/__init__.py | 133 +++++++++++++++++++++-------- 2 files changed, 104 insertions(+), 39 deletions(-) diff --git a/doc/source/whatsnew.yml b/doc/source/whatsnew.yml index 0857e70eb..192381c52 100644 --- a/doc/source/whatsnew.yml +++ b/doc/source/whatsnew.yml @@ -4,7 +4,7 @@ fragments: content: | Open the current project with Mechanical GUI. - .. code:: python + .. code-block:: python from ansys.mechanical.core import App @@ -12,13 +12,13 @@ fragments: app.save() app.launch_gui() - Above code opens up the temporarily saved ``.mechdb`` or ``.mechdat`` files. + **Above** code opens up the *temporarily* saved ``.mechdb`` or `.mechdat` files. The files are deleted when GUI is closed . For more info check - `launch_gui() <../api/ansys/mechanical/core/embedding/launch_gui/index.html>`_ function + content ``before`` `launch_gui() <./user-guide/autoapi.html>`_ function `another link `_ more `words`. Opens up the specified project file. - .. code:: python + .. sourcecode:: python launch_gui("path/to/project.mechdb") @@ -28,7 +28,7 @@ fragments: This feature let you see the heirachial Mechanical project tree. It also shows whether an object is suppressed or not. - .. code:: python + .. code:: import ansys.mechanical.core as mech diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 01c558c42..1525c830c 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -22,7 +22,7 @@ """Module for the Ansys Sphinx theme.""" -from itertools import tee +from itertools import islice, tee import logging import os import pathlib @@ -719,27 +719,36 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): content_lines = fragment["content"].split("\n") # Create iterator for the content_lines - content_iterator = iter(enumerate(content_lines)) - iterator_copy, content_iterator = tee(iter(enumerate(content_lines))) + content_iterator = iter(content_lines) + line = next(content_iterator, None) - for line_index, line in content_iterator: - next(iterator_copy, None) - if ".. code" in line: - code_block = create_code_block(content_iterator, iterator_copy) + while line is not None: + if ".. code" in line or ".. sourcecode" in line: + code_block, line = create_code_block(content_iterator, line) whatsnew_dropdown += code_block else: - whatsnew_dropdown += nodes.line("sd-card-text", line) + paragraph, line = create_paragraph(content_iterator, line) + whatsnew_dropdown += paragraph minor_version_whatsnew.append(whatsnew_dropdown) return minor_version_whatsnew -def create_code_block(content_iterator, iterator_copy): - code_block = nodes.container(classes=["highlight-python notranslate"]) +def create_code_block(content_iterator, line): + # Get language after "code::" + language = line.split("::")[1].strip() + if language: + # maybe not this: nodes.container(classes=["code-block"]) + code_block = nodes.container(classes=[f"highlight-{language} notranslate"]) + else: + code_block = nodes.container() + + # classes=["highlight"] is required for the copy button to show up in the literal_block highlight_container = nodes.container(classes=["highlight"]) # Create literal block with copy button + # nodes.literal_block(classes=[f"language-{language}"]) literal_block = nodes.literal_block( classes=["sd-button sd-button--icon sd-button--icon-only sd-button--icon-small"], icon="copy", @@ -748,38 +757,94 @@ def create_code_block(content_iterator, iterator_copy): ) next_line = next(content_iterator, None) - next_line_copy = next(iterator_copy, None) - if next_line is not None: - while next_line[1].startswith(" ") or (next_line[1] == ""): - formatted_line = next_line[1].lstrip() + "\n" - literal_block += nodes.inline(text=formatted_line) + while next_line is not None and (next_line.startswith(" ") or (next_line == "")): + formatted_line = next_line.lstrip() + "\n" + literal_block += nodes.inline(text=formatted_line) - next_line_copy = next(iterator_copy, None) - if next_line_copy is not None: - if next_line_copy[1].startswith(" ") or next_line_copy[1] == "": - next_line = next(content_iterator, None) - else: - break - else: - break + if next_line is not None: + next_line = next(content_iterator, None) + else: + break - highlight_container += literal_block + highlight_container += literal_block code_block += highlight_container - return code_block + return code_block, next_line + + +def create_paragraph(content_iterator, current_line): + paragraph = nodes.paragraph("sd-card-text") + paragraph.append(nodes.inline(text=current_line)) + + next_line = next(content_iterator, None) + + while next_line is not None and not next_line.startswith(".. "): + # Regular expressions to find rst links, single backticks, and double backticks + rst_link_regex = r"(`([^<`]+?) <([^>`]+?)>`_)" + single_backtick_regex = r"(`([^`]+?)`)" + double_backtick_regex = r"(``(.*?)``)" + + # Check if there are single or double backticks, or an RST link in the line + link_backtick_regex = rf"{rst_link_regex}|{single_backtick_regex}|{double_backtick_regex}" + + # Get all matches for backticks and rst links in the line + matches = re.findall(link_backtick_regex, next_line) + + if matches: + link_backtick_dict = {} + regex_matches = [] + for match in matches: + if match[0] != "": + regex_matches.append(match[0]) + link_backtick_dict[match[0]] = {"name": match[1], "url": match[2]} + if match[3] != "": + regex_matches.append(match[3]) + link_backtick_dict[match[3]] = {"content": match[4]} + if match[5] != "": + regex_matches.append(match[5]) + link_backtick_dict[match[5]] = {"content": match[6]} + + # Create a regular expression pattern that matches any URL + pattern = "|".join(map(re.escape, regex_matches)) + + # Split the line using the pattern + split_lines = re.split(f"({pattern})", next_line) + + for line in split_lines: + if line in regex_matches: + # If it matches rst_link_regex, append a reference node + if re.search(rst_link_regex, line): + url = link_backtick_dict[line]["url"] + if url.startswith("http") or url.startswith("www"): + ref_type = "external" + else: + ref_type = "internal" + paragraph.append( + nodes.reference( + classes=[f"reference-{ref_type}"], + refuri=url, + href=url, + text=link_backtick_dict[line]["name"], + ) + ) + elif re.search(single_backtick_regex, line) or re.search( + double_backtick_regex, line + ): + paragraph.append(nodes.literal(text=link_backtick_dict[line]["content"])) + else: + paragraph.append(nodes.inline(text=line)) + else: + paragraph.append(nodes.inline(text=next_line)) + if next_line is not None: + # Check if there are backticks in the line + next_line = next(content_iterator, None) + else: + break -# def has_next(iterator): -# # Create a copy of the iterator -# iterator_copy, iterator = tee(iterator) -# try: -# # Try to get the next item from the copy -# next(iterator_copy) -# return True -# except StopIteration: -# return False + return paragraph, next_line def extract_whatsnew(app, doctree, docname): From 8c397e9b9c5c66bf7715694dd3ef45516880942c Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:39:20 -0500 Subject: [PATCH 42/73] adjust code block and paragraph generation & update whatsnew.yml file --- doc/source/whatsnew.yml | 4 +-- src/ansys_sphinx_theme/__init__.py | 42 ++++++++++++++++++------------ 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/doc/source/whatsnew.yml b/doc/source/whatsnew.yml index 192381c52..dd7219447 100644 --- a/doc/source/whatsnew.yml +++ b/doc/source/whatsnew.yml @@ -12,8 +12,8 @@ fragments: app.save() app.launch_gui() - **Above** code opens up the *temporarily* saved ``.mechdb`` or `.mechdat` files. - The files are deleted when GUI is closed . For more info check + The above code opens up the *temporarily* saved ``.mechdb`` or `.mechdat` files. + The files are **deleted** when the GUI is closed. For more information, check the content ``before`` `launch_gui() <./user-guide/autoapi.html>`_ function `another link `_ more `words`. Opens up the specified project file. diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 1525c830c..b108ef40d 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -724,10 +724,23 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): while line is not None: if ".. code" in line or ".. sourcecode" in line: - code_block, line = create_code_block(content_iterator, line) + # Get language after "code::" + language = line.split("::")[1].strip() + # Create the code block container node + code_block = ( + nodes.container(classes=[f"highlight-{language} notranslate"]) + if language + else nodes.container() + ) + + code_block, line = fill_code_block(content_iterator, code_block) whatsnew_dropdown += code_block else: - paragraph, line = create_paragraph(content_iterator, line) + # Create the paragraph node and add the first line to it + paragraph = nodes.paragraph("sd-card-text") + paragraph.append(nodes.inline(text=f"{line} ")) + + paragraph, line = fill_paragraph(content_iterator, paragraph) whatsnew_dropdown += paragraph minor_version_whatsnew.append(whatsnew_dropdown) @@ -735,15 +748,7 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): return minor_version_whatsnew -def create_code_block(content_iterator, line): - # Get language after "code::" - language = line.split("::")[1].strip() - if language: - # maybe not this: nodes.container(classes=["code-block"]) - code_block = nodes.container(classes=[f"highlight-{language} notranslate"]) - else: - code_block = nodes.container() - +def fill_code_block(content_iterator, code_block): # classes=["highlight"] is required for the copy button to show up in the literal_block highlight_container = nodes.container(classes=["highlight"]) @@ -774,10 +779,7 @@ def create_code_block(content_iterator, line): return code_block, next_line -def create_paragraph(content_iterator, current_line): - paragraph = nodes.paragraph("sd-card-text") - paragraph.append(nodes.inline(text=current_line)) - +def fill_paragraph(content_iterator, paragraph): next_line = next(content_iterator, None) while next_line is not None and not next_line.startswith(".. "): @@ -814,7 +816,7 @@ def create_paragraph(content_iterator, current_line): for line in split_lines: if line in regex_matches: - # If it matches rst_link_regex, append a reference node + # If it matches RST link regex, append a reference node if re.search(rst_link_regex, line): url = link_backtick_dict[line]["url"] if url.startswith("http") or url.startswith("www"): @@ -829,6 +831,7 @@ def create_paragraph(content_iterator, current_line): text=link_backtick_dict[line]["name"], ) ) + # If it matches single or double backticks, append a literal node elif re.search(single_backtick_regex, line) or re.search( double_backtick_regex, line ): @@ -836,7 +839,12 @@ def create_paragraph(content_iterator, current_line): else: paragraph.append(nodes.inline(text=line)) else: - paragraph.append(nodes.inline(text=next_line)) + paragraph.append(nodes.inline(text=next_line)) if next_line != "" else paragraph.append( + nodes.line(text="\n") + ) + + # Add a space at the end of each line + paragraph.append(nodes.inline(text=" ")) if next_line is not None: # Check if there are backticks in the line From ddaa4dc0b7e8f51131b5736108033f9d3d55f6ec Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:52:05 -0500 Subject: [PATCH 43/73] handle all paragraph lines within fill_paragraph and update whatsnew.yml --- doc/source/whatsnew.yml | 2 +- src/ansys_sphinx_theme/__init__.py | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/source/whatsnew.yml b/doc/source/whatsnew.yml index dd7219447..6c498006c 100644 --- a/doc/source/whatsnew.yml +++ b/doc/source/whatsnew.yml @@ -25,7 +25,7 @@ fragments: - title: Print Mechanical tree version: 0.16.6 content: | - This feature let you see the heirachial Mechanical project tree. + This feature lets you see the hierarchical Mechanical project tree. It also shows whether an object is suppressed or not. .. code:: diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index b108ef40d..d0c5dcba0 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -726,21 +726,24 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): if ".. code" in line or ".. sourcecode" in line: # Get language after "code::" language = line.split("::")[1].strip() - # Create the code block container node + # Create the code block container node with the language if it exists code_block = ( nodes.container(classes=[f"highlight-{language} notranslate"]) if language else nodes.container() ) + # Fill the code block with the following lines until it reaches the end or an + # unindented line code_block, line = fill_code_block(content_iterator, code_block) whatsnew_dropdown += code_block else: - # Create the paragraph node and add the first line to it + # Create the paragraph node paragraph = nodes.paragraph("sd-card-text") - paragraph.append(nodes.inline(text=f"{line} ")) - paragraph, line = fill_paragraph(content_iterator, paragraph) + # Fill the paragraph node with the following lines until it reaches + # the end or a code block + paragraph, line = fill_paragraph(content_iterator, paragraph, line) whatsnew_dropdown += paragraph minor_version_whatsnew.append(whatsnew_dropdown) @@ -779,9 +782,7 @@ def fill_code_block(content_iterator, code_block): return code_block, next_line -def fill_paragraph(content_iterator, paragraph): - next_line = next(content_iterator, None) - +def fill_paragraph(content_iterator, paragraph, next_line): while next_line is not None and not next_line.startswith(".. "): # Regular expressions to find rst links, single backticks, and double backticks rst_link_regex = r"(`([^<`]+?) <([^>`]+?)>`_)" @@ -839,6 +840,8 @@ def fill_paragraph(content_iterator, paragraph): else: paragraph.append(nodes.inline(text=line)) else: + # Append the next_line as an inline element, unless it is an empty string. If it's an + # empty string, append a line break paragraph.append(nodes.inline(text=next_line)) if next_line != "" else paragraph.append( nodes.line(text="\n") ) From 427f728d3c7cdd44b25449af3a79d0254552a162 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:06:03 -0500 Subject: [PATCH 44/73] add comments and docstrings to functions --- src/ansys_sphinx_theme/__init__.py | 103 ++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 23 deletions(-) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index d0c5dcba0..d24e1f219 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -28,7 +28,7 @@ import pathlib import re import subprocess -from typing import Any, Dict +from typing import Any, Dict, Iterable from docutils import nodes from sphinx import addnodes @@ -698,7 +698,7 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): ) minor_version_whatsnew += nodes.title("", "What's New") - # For each fragment in the what's new yaml file, add the content as a paragraph + # Add a dropdown under the "What's New" section for each fragment in the whatsnew.yml file for fragment in whatsnew_data["fragments"]: if minor_version in fragment["version"]: whatsnew_dropdown = nodes.container( @@ -720,6 +720,8 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): # Create iterator for the content_lines content_iterator = iter(content_lines) + + # Navigate to first line in the iterator line = next(content_iterator, None) while line is not None: @@ -746,17 +748,31 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): paragraph, line = fill_paragraph(content_iterator, paragraph, line) whatsnew_dropdown += paragraph + # Append the fragment dropdown to the minor_version_whatsnew section minor_version_whatsnew.append(whatsnew_dropdown) return minor_version_whatsnew -def fill_code_block(content_iterator, code_block): +def fill_code_block(content_iterator: Iterable, code_block: nodes.container) -> nodes.container: + """Fill the code block. + + Parameters + ---------- + content_iterator : Iterable + Iterator for the content lines from the fragments in the whatsnew.yml file. + code_block : nodes.container + Container node for the code block. + + Returns + ------- + nodes.container, str + Container node for the code block and the next line in the content iterator. + """ # classes=["highlight"] is required for the copy button to show up in the literal_block highlight_container = nodes.container(classes=["highlight"]) # Create literal block with copy button - # nodes.literal_block(classes=[f"language-{language}"]) literal_block = nodes.literal_block( classes=["sd-button sd-button--icon sd-button--icon-only sd-button--icon-small"], icon="copy", @@ -764,50 +780,84 @@ def fill_code_block(content_iterator, code_block): title="Copy", ) + # Move to the first line in the code block (the line after ".. code::") next_line = next(content_iterator, None) + # While the next_line is indented or blank, add it to the code block while next_line is not None and (next_line.startswith(" ") or (next_line == "")): formatted_line = next_line.lstrip() + "\n" + # Add the formatted line to the literal block literal_block += nodes.inline(text=formatted_line) + # Break the loop if the end of the content is reached if next_line is not None: + # Move to the next line in the content next_line = next(content_iterator, None) else: break + # Add the literal block to the highlight container highlight_container += literal_block + # Add the highlight container to the code block code_block += highlight_container return code_block, next_line -def fill_paragraph(content_iterator, paragraph, next_line): - while next_line is not None and not next_line.startswith(".. "): - # Regular expressions to find rst links, single backticks, and double backticks - rst_link_regex = r"(`([^<`]+?) <([^>`]+?)>`_)" - single_backtick_regex = r"(`([^`]+?)`)" - double_backtick_regex = r"(``(.*?)``)" +def fill_paragraph( + content_iterator: Iterable, paragraph: nodes.paragraph, next_line: str +) -> nodes.paragraph: + """Fill the paragraph node. - # Check if there are single or double backticks, or an RST link in the line - link_backtick_regex = rf"{rst_link_regex}|{single_backtick_regex}|{double_backtick_regex}" + Parameters + ---------- + content_iterator : Iterable + Iterator for the content lines from the fragments in the whatsnew.yml file. + paragraph : nodes.paragraph + Paragraph node. + next_line : str + Next line in the content iterator. - # Get all matches for backticks and rst links in the line + Returns + ------- + nodes.paragraph, str + Paragraph node and the next line in the content iterator. + """ + # While the next_line is not None and is not a code block, add it to the paragraph + while next_line is not None and not next_line.startswith(".. "): + # Regular expressions to find rst links, and single & double backticks/asterisks + rst_link_regex = r"(`([^<`]+?) <([^>`]+?)>`_)" # indices 0, 1, & 2 + single_backtick_regex = r"(`([^`]+?)`)" # indices 3 & 4 + double_backtick_regex = r"(``(.*?)``)" # indices 5 & 6 + bold_text_regex = r"(\*\*(.*?)\*\*)" # indices 7 & 8 + italic_text_regex = r"(\*([^\*]+?)\*)" # indices 9 & 10 + + # Check if there are rst links, single & double backticks/asterisks in the line + link_backtick_regex = ( + rf"{rst_link_regex}|" + rf"{single_backtick_regex}|{double_backtick_regex}|" + rf"{bold_text_regex}|{italic_text_regex}" + ) + + # Get all matches for rst links, single & double backticks/asterisks in the line matches = re.findall(link_backtick_regex, next_line) if matches: + # Create a dictionary to store the matches and their replacements link_backtick_dict = {} regex_matches = [] for match in matches: - if match[0] != "": - regex_matches.append(match[0]) - link_backtick_dict[match[0]] = {"name": match[1], "url": match[2]} - if match[3] != "": - regex_matches.append(match[3]) - link_backtick_dict[match[3]] = {"content": match[4]} - if match[5] != "": - regex_matches.append(match[5]) - link_backtick_dict[match[5]] = {"content": match[6]} + for i in range(len(match)): + if i == 0 or i == 3 or i == 5 or i == 7 or i == 9: + regex_matches.append(match[i]) + if i == 0: + link_backtick_dict[match[i]] = { + "name": match[i + 1], + "url": match[i + 2], + } + else: + link_backtick_dict[match[i]] = {"content": match[i + 1]} # Create a regular expression pattern that matches any URL pattern = "|".join(map(re.escape, regex_matches)) @@ -837,6 +887,12 @@ def fill_paragraph(content_iterator, paragraph, next_line): double_backtick_regex, line ): paragraph.append(nodes.literal(text=link_backtick_dict[line]["content"])) + # If it matches bold text, append a strong node + elif re.search(bold_text_regex, line): + paragraph.append(nodes.strong(text=link_backtick_dict[line]["content"])) + # If it matches italic text, append an emphasis node + elif re.search(italic_text_regex, line): + paragraph.append(nodes.emphasis(text=link_backtick_dict[line]["content"])) else: paragraph.append(nodes.inline(text=line)) else: @@ -849,8 +905,9 @@ def fill_paragraph(content_iterator, paragraph, next_line): # Add a space at the end of each line paragraph.append(nodes.inline(text=" ")) + # Break the loop if the end of the content is reached if next_line is not None: - # Check if there are backticks in the line + # Move to the next line in the content next_line = next(content_iterator, None) else: break From ac518b60c664962527495daefb83839c291a20b8 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:49:35 -0500 Subject: [PATCH 45/73] add example strings for code that could be confusing --- doc/source/whatsnew.yml | 2 +- src/ansys_sphinx_theme/__init__.py | 54 +++++++++++++++--------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/doc/source/whatsnew.yml b/doc/source/whatsnew.yml index 6c498006c..bee0c0802 100644 --- a/doc/source/whatsnew.yml +++ b/doc/source/whatsnew.yml @@ -13,7 +13,7 @@ fragments: app.launch_gui() The above code opens up the *temporarily* saved ``.mechdb`` or `.mechdat` files. - The files are **deleted** when the GUI is closed. For more information, check the + The files are **deleted** when the ``GUI`` is closed. For more information, check the content ``before`` `launch_gui() <./user-guide/autoapi.html>`_ function `another link `_ more `words`. Opens up the specified project file. diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index d24e1f219..ee0f935e9 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -827,11 +827,11 @@ def fill_paragraph( # While the next_line is not None and is not a code block, add it to the paragraph while next_line is not None and not next_line.startswith(".. "): # Regular expressions to find rst links, and single & double backticks/asterisks - rst_link_regex = r"(`([^<`]+?) <([^>`]+?)>`_)" # indices 0, 1, & 2 - single_backtick_regex = r"(`([^`]+?)`)" # indices 3 & 4 - double_backtick_regex = r"(``(.*?)``)" # indices 5 & 6 - bold_text_regex = r"(\*\*(.*?)\*\*)" # indices 7 & 8 - italic_text_regex = r"(\*([^\*]+?)\*)" # indices 9 & 10 + rst_link_regex = r"(`[^<`]+? <[^>`]+?>`_)" + single_backtick_regex = r"(`[^`]+?`)" + double_backtick_regex = r"(``.*?``)" + bold_text_regex = r"(\*\*.*?\*\*)" + italic_text_regex = r"(\*[^\*]+?\*)" # Check if there are rst links, single & double backticks/asterisks in the line link_backtick_regex = ( @@ -841,35 +841,31 @@ def fill_paragraph( ) # Get all matches for rst links, single & double backticks/asterisks in the line + # Sample: next_line = "The files are **deleted** when the ``GUI`` is closed. For more info" + # For example, matches = [('', '', '', '**deleted**', ''), ('', '', '``GUI``', '', '')] matches = re.findall(link_backtick_regex, next_line) if matches: - # Create a dictionary to store the matches and their replacements - link_backtick_dict = {} - regex_matches = [] - for match in matches: - for i in range(len(match)): - if i == 0 or i == 3 or i == 5 or i == 7 or i == 9: - regex_matches.append(match[i]) - if i == 0: - link_backtick_dict[match[i]] = { - "name": match[i + 1], - "url": match[i + 2], - } - else: - link_backtick_dict[match[i]] = {"content": match[i + 1]} + # Get all of the matches from the matches list + # For example, regex_matches = ['**deleted**', '``GUI``'] + regex_matches = [ + element for match in matches for i, element in enumerate(match) if element + ] # Create a regular expression pattern that matches any URL + # For example, pattern = r"\*\*deleted\*\*|``GUI``" pattern = "|".join(map(re.escape, regex_matches)) # Split the line using the pattern + # For example, split_lines = ['The files are ', '**deleted**', ' when the ', '``GUI``', + # ' is closed. For more info'] split_lines = re.split(f"({pattern})", next_line) for line in split_lines: if line in regex_matches: # If it matches RST link regex, append a reference node if re.search(rst_link_regex, line): - url = link_backtick_dict[line]["url"] + text, url = re.findall(r"`([^<`]+?) <([^>`]+?)>`_", line)[0] if url.startswith("http") or url.startswith("www"): ref_type = "external" else: @@ -879,20 +875,24 @@ def fill_paragraph( classes=[f"reference-{ref_type}"], refuri=url, href=url, - text=link_backtick_dict[line]["name"], + text=text, ) ) # If it matches single or double backticks, append a literal node - elif re.search(single_backtick_regex, line) or re.search( - double_backtick_regex, line - ): - paragraph.append(nodes.literal(text=link_backtick_dict[line]["content"])) + elif re.search(single_backtick_regex, line): + text = re.findall(r"`([^`]+?)`", line)[0] + paragraph.append(nodes.literal(text=text)) + elif re.search(double_backtick_regex, line): + text = re.findall(r"``(.*?)``", line)[0] + paragraph.append(nodes.literal(text=text)) # If it matches bold text, append a strong node elif re.search(bold_text_regex, line): - paragraph.append(nodes.strong(text=link_backtick_dict[line]["content"])) + text = re.findall(r"\*\*(.*?)\*\*", line)[0] + paragraph.append(nodes.strong(text=text)) # If it matches italic text, append an emphasis node elif re.search(italic_text_regex, line): - paragraph.append(nodes.emphasis(text=link_backtick_dict[line]["content"])) + text = re.findall(r"\*([^\*]+?)\*", line)[0] + paragraph.append(nodes.emphasis(text=text)) else: paragraph.append(nodes.inline(text=line)) else: From f1ccdebf62523eb98574c90f18a3679aa155372a Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 14 Jan 2025 18:02:02 -0500 Subject: [PATCH 46/73] add line specifying which version the fragment is available in --- src/ansys_sphinx_theme/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index ee0f935e9..ff2c536e0 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -715,6 +715,13 @@ def add_whatsnew_to_minor_version(minor_version, whatsnew_data): ) whatsnew_dropdown += nodes.rubric("", fragment["title"]) + # Add a line specifying which version the fragment is available in + version_paragraph = nodes.paragraph("sd-card-text") + version_paragraph.append( + nodes.emphasis("", f"Available in v{fragment['version']} and later") + ) + whatsnew_dropdown += version_paragraph + # Split content from YAML file into list content_lines = fragment["content"].split("\n") From ab2bc8a4f7b303ca6a93b67aec9a04684aa62528 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Wed, 15 Jan 2025 10:10:28 -0500 Subject: [PATCH 47/73] add PyYAML dependency to doc & changelog --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 5fe3e57a5..b8a5971a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,6 +45,7 @@ doc = [ "Pillow>=9.0", "PyGitHub==2.5.0", "pyvista[jupyter]==0.44.2", + "PyYAML==6.0.2", "requests==2.32.3", "Sphinx==8.1.3", "sphinx-autoapi==3.4.0", @@ -55,6 +56,7 @@ doc = [ "sphinx-notfound-page==1.0.4", ] changelog = [ + "PyYAML==6.0.2", "sphinx-design==0.6.1", ] From dc89dc6e6d572db23ee6ca5faf18c798afc9fea6 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:11:49 +0000 Subject: [PATCH 48/73] chore: adding changelog file 583.miscellaneous.md [dependabot-skip] --- doc/changelog.d/{583.documentation.md => 583.miscellaneous.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/changelog.d/{583.documentation.md => 583.miscellaneous.md} (100%) diff --git a/doc/changelog.d/583.documentation.md b/doc/changelog.d/583.miscellaneous.md similarity index 100% rename from doc/changelog.d/583.documentation.md rename to doc/changelog.d/583.miscellaneous.md From d9373ee8dd236b1b9909c4428ef2d000e2d1efcd Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Wed, 15 Jan 2025 10:29:14 -0500 Subject: [PATCH 49/73] update init header and fix link in whatsnew.yml --- doc/source/whatsnew.yml | 2 +- src/ansys_sphinx_theme/templates/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew.yml b/doc/source/whatsnew.yml index bee0c0802..74e1ba246 100644 --- a/doc/source/whatsnew.yml +++ b/doc/source/whatsnew.yml @@ -14,7 +14,7 @@ fragments: The above code opens up the *temporarily* saved ``.mechdb`` or `.mechdat` files. The files are **deleted** when the ``GUI`` is closed. For more information, check the - content ``before`` `launch_gui() <./user-guide/autoapi.html>`_ function `another link `_ more `words`. + content ``before`` `launch_gui() `_ function `another link `_ more `words`. Opens up the specified project file. diff --git a/src/ansys_sphinx_theme/templates/__init__.py b/src/ansys_sphinx_theme/templates/__init__.py index 920b91de7..a6565c3ae 100644 --- a/src/ansys_sphinx_theme/templates/__init__.py +++ b/src/ansys_sphinx_theme/templates/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2021 - 2024 ANSYS, Inc. and/or its affiliates. +# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # # From 2a627e616ff4f608c4bc6e6594ed7fdca4d8781f Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Thu, 16 Jan 2025 17:40:00 -0500 Subject: [PATCH 50/73] adjust what's new sidebar --- LICENSE | 42 +- doc/source/conf.py | 609 ++++---- doc/source/whatsnew.yml | 170 ++- src/ansys_sphinx_theme/__init__.py | 2121 ++++++++++++++-------------- 4 files changed, 1501 insertions(+), 1441 deletions(-) diff --git a/LICENSE b/LICENSE index 4a8652561..3df6f8200 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2021 - 2025 ANSYS, Inc. and/or its affiliates. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2021 - 2025 ANSYS, Inc. and/or its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/doc/source/conf.py b/doc/source/conf.py index 4e9c5b540..0c46c4430 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -1,303 +1,306 @@ -"""Sphinx documentation configuration file.""" - -from datetime import datetime -import os -from pathlib import Path -from typing import List - -from github import Github -import pyvista -import requests -from sphinx.builders.latex import LaTeXBuilder - -from ansys_sphinx_theme import ( - ALL_NODES, - PARAGRAPHS, - TITLES, - __version__, - ansys_favicon, - ansys_logo_white, - ansys_logo_white_cropped, - generate_404, - get_version_match, - latex, - watermark, -) - -THIS_PATH = Path(__file__).parent.resolve() -EXAMPLE_PATH = (THIS_PATH / "examples" / "sphinx_examples").resolve() - -# Project information -project = "ansys_sphinx_theme" -copyright = f"(c) {datetime.now().year} ANSYS, Inc. All rights reserved" -author = "ANSYS, Inc." -release = version = __version__ -cname = os.getenv("DOCUMENTATION_CNAME", "sphinxdocs.ansys.com") -switcher_version = get_version_match(__version__) - -# HTML configuration -html_favicon = ansys_favicon -html_theme = "ansys_sphinx_theme" -html_short_title = html_title = "Ansys Sphinx Theme" -html_static_path = ["_static"] -templates_path = ["_templates"] - -html_context = { - "github_user": "ansys", - "github_repo": "ansys-sphinx-theme", - "github_version": "main", - "doc_path": "doc/source", - "page_assets": { - "examples/table": { - "needs_datatables": True, - }, - }, -} - -html_theme_options = { - "github_url": "https://github.com/ansys/ansys-sphinx-theme", - "contact_mail": "pyansys.support@ansys.com", - "use_edit_page_button": True, - "additional_breadcrumbs": [ - ("PyAnsys", "https://docs.pyansys.com/"), - ], - "switcher": { - "json_url": f"https://{cname}/versions.json", - "version_match": get_version_match(__version__), - }, - "logo": "ansys", - "static_search": { - "threshold": 0.2, - "limit": 7, - "minMatchCharLength": 3, - }, - "whatsnew": { - "file": "changelog", - "pages": ["index", "changelog"], - }, -} - -index_patterns = { - "examples/api/": ALL_NODES, - "examples/sphinx_examples/": TITLES + PARAGRAPHS, -} - - -# Sphinx extensions -extensions = [ - "numpydoc", - "sphinx_design", - "sphinx.ext.autodoc", - "sphinx.ext.autosummary", - "sphinx.ext.intersphinx", - "sphinx.ext.todo", - "sphinx_copybutton", - "sphinx.ext.intersphinx", - "sphinx.ext.todo", - "notfound.extension", - "sphinx_jinja", -] - -# Intersphinx mapping -intersphinx_mapping = { - "python": ("https://docs.python.org/3", None), - "sphinx": ("https://www.sphinx-doc.org/en/master", None), -} - -# numpydoc configuration -numpydoc_show_class_members = False -numpydoc_xref_param_type = True -numpydoc_validate = True -numpydoc_validation_checks = { - "GL06", # Found unknown section - "GL07", # Sections are in the wrong order. - "GL09", # Deprecation warning should precede extended summary - "GL10", # reST directives {directives} must be followed by two colons - "SS01", # No summary found - "SS02", # Summary does not start with a capital letter - "SS04", # Summary contains heading whitespaces - "RT02", # The first line of the Returns section should contain only the type -} - -suppress_warnings = ["config.cache"] - -# The suffix(es) of source filenames. -source_suffix = ".rst" - -# The master toctree document. -master_doc = "index" - -# additional logos for the latex coverpage -LaTeXBuilder.supported_image_types = ["image/png", "image/pdf", "image/svg+xml"] -latex_additional_files = [watermark, ansys_logo_white, ansys_logo_white_cropped] -latex_elements = {"preamble": latex.generate_preamble(html_title)} - -# Not found page -notfound_context = { - "body": generate_404(), -} -notfound_no_urls_prefix = True - -# ONLY FOR ANSYS-SPHINX-THEME -exclude_patterns = [ - "links.rst", - "examples/sphinx-gallery/README.rst", - "examples/gallery-examples/*.ipynb", - "sg_execution_times.rst", -] -rst_epilog = "" -with Path.open(THIS_PATH / "links.rst", "r") as f: - rst_epilog += f.read() - - -linkcheck_ignore = [ - r"https://sphinxdocs.ansys.com/version/*", -] -if switcher_version != "dev": - linkcheck_ignore.append( - f"https://github.com/ansys/ansys-sphinx-theme/releases/tag/v{__version__}" - ) - - -# Configure the Jinja contexts - -jinja_contexts = { - "install_guide": { - "version": f"v{version}" if not version.endswith("dev0") else "main", - }, - "pdf_guide": {"version": get_version_match(__version__)}, # noqa: E501 -} - - -def extract_example_links( - repo_fullname: str, path_relative_to_root: str, exclude_files: List[str] = [] -) -> List[str]: - """ - Extract example links from a specific GitHub repository. - - Parameters - ---------- - repo_fullname : str - Fullname of the repository to extract example links from. - path_relative_to_root : str - Path relative to the root of the repository to extract example links from. - exclude_files : list of str - A list of files to exclude from the returned example links. - - Returns - ------- - list - List of example links. - """ - g = Github() - repo = g.get_repo(repo_fullname) - contents = repo.get_contents(path_relative_to_root) - if not isinstance(contents, list): - contents = [contents] - example_links = [] - for content in contents: - if content.type == "dir": - example_links.extend(extract_example_links(repo_fullname, content.path, exclude_files)) - elif content.type == "file": - if content.name not in exclude_files: - example_links.append(content.download_url) - - return example_links - - -def download_and_process_files(example_links: List[str]) -> List[str]: - """Download and process a series of example files. - - This function downloads a series of example files using a - list of links and processes each file. - - Parameters - ---------- - example_links : List[str] - List of links to the example files to be downloaded. - - Returns - ------- - list - List of the names of the processed files. - """ - file_names = [] - for link in example_links: - file_name = link.split("/")[-1] - file_path = str((EXAMPLE_PATH / file_name).absolute()) - with open(file_path, "wb") as f: # noqa: PTH123 - response = requests.get(link) - content = response.content.decode() - lines = content.splitlines() - # Replace the "target" string with the file name in the example files - f.write("\n".join([line.replace("target", file_name) for line in lines]).encode()) - file_names.append(file_name) - - return file_names - - -# Skip building examples if desired -BUILD_EXAMPLES = True if os.environ.get("BUILD_EXAMPLES", "true") == "true" else False -jinja_contexts["main_toctree"] = {"build_examples": BUILD_EXAMPLES} - -if not BUILD_EXAMPLES: - exclude_patterns.extend(["examples.rst", "examples/**", "examples/api/**"]) - - -else: - # Autoapi examples - extensions.append("ansys_sphinx_theme.extension.autoapi") - html_theme_options["ansys_sphinx_theme_autoapi"] = { - "project": project, - "directory": "src/ansys_sphinx_theme/examples", - "output": "examples/api", - "own_page_level": "function", - "package_depth": 1, - } - - # Gallery of examples - extensions.extend(["nbsphinx", "sphinx_gallery.gen_gallery"]) - sphinx_gallery_conf = { - # path to your examples scripts - "examples_dirs": ["examples/sphinx-gallery"], - # path where to save gallery generated examples - "gallery_dirs": ["examples/gallery-examples"], - # Pattern to search for example files - "filename_pattern": r"sphinx_gallery\.py", - # Remove the "Download all examples" button from the top level gallery - "download_all_examples": False, - # Modules for which function level galleries are created. In - "image_scrapers": ("pyvista", "matplotlib"), - "default_thumb_file": "source/_static/pyansys_light_square.png", - } - - nbsphinx_prolog = """ -Download this example as a :download:`Jupyter notebook `. - ----- -""" - nbsphinx_execute = "always" - nbsphinx_thumbnails = { - "examples/nbsphinx/jupyter-notebook": "_static/pyansys_light_square.png", - } - - pyvista.BUILDING_GALLERY = True - - # Third party examples - example_links = extract_example_links( - "executablebooks/sphinx-design", - "docs/snippets/rst", - exclude_files=["article-info.txt"], - ) - file_names = download_and_process_files(example_links) - - admonitions_links = extract_example_links( - "pydata/pydata-sphinx-theme", - "docs/examples/kitchen-sink/admonitions.rst", - ) - - admonitions_links = download_and_process_files(admonitions_links) - todo_include_todos = True # admonition todo needs this to be True - - jinja_contexts["examples"] = {"inputs_examples": file_names} - jinja_contexts["admonitions"] = {"inputs_admonitions": admonitions_links} +"""Sphinx documentation configuration file.""" + +from datetime import datetime +import os +from pathlib import Path +from typing import List + +from github import Github +import pyvista +import requests +from sphinx.builders.latex import LaTeXBuilder + +from ansys_sphinx_theme import ( + ALL_NODES, + PARAGRAPHS, + TITLES, + __version__, + ansys_favicon, + ansys_logo_white, + ansys_logo_white_cropped, + generate_404, + get_version_match, + latex, + watermark, +) + +THIS_PATH = Path(__file__).parent.resolve() +EXAMPLE_PATH = (THIS_PATH / "examples" / "sphinx_examples").resolve() + +# Project information +project = "ansys_sphinx_theme" +copyright = f"(c) {datetime.now().year} ANSYS, Inc. All rights reserved" +author = "ANSYS, Inc." +release = version = __version__ +cname = os.getenv("DOCUMENTATION_CNAME", "sphinxdocs.ansys.com") +switcher_version = get_version_match(__version__) + +# HTML configuration +html_favicon = ansys_favicon +html_theme = "ansys_sphinx_theme" +html_short_title = html_title = "Ansys Sphinx Theme" +html_static_path = ["_static"] +templates_path = ["_templates"] + +html_context = { + "github_user": "ansys", + "github_repo": "ansys-sphinx-theme", + "github_version": "main", + "doc_path": "doc/source", + "page_assets": { + "examples/table": { + "needs_datatables": True, + }, + }, +} + +html_theme_options = { + "github_url": "https://github.com/ansys/ansys-sphinx-theme", + "contact_mail": "pyansys.support@ansys.com", + "use_edit_page_button": True, + "additional_breadcrumbs": [ + ("PyAnsys", "https://docs.pyansys.com/"), + ], + "switcher": { + "json_url": f"https://{cname}/versions.json", + "version_match": get_version_match(__version__), + }, + "logo": "ansys", + "static_search": { + "threshold": 0.2, + "limit": 7, + "minMatchCharLength": 3, + }, + "whatsnew": { + "no_of_headers": 2, + "no_of_contents": 1, + "whatsnew_file": "whatsnew", + "changelog_file": "changelog", + "pages": ["changelog"], # "index" + }, +} + +index_patterns = { + "examples/api/": ALL_NODES, + "examples/sphinx_examples/": TITLES + PARAGRAPHS, +} + + +# Sphinx extensions +extensions = [ + "numpydoc", + "sphinx_design", + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.intersphinx", + "sphinx.ext.todo", + "sphinx_copybutton", + "sphinx.ext.intersphinx", + "sphinx.ext.todo", + "notfound.extension", + "sphinx_jinja", +] + +# Intersphinx mapping +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "sphinx": ("https://www.sphinx-doc.org/en/master", None), +} + +# numpydoc configuration +numpydoc_show_class_members = False +numpydoc_xref_param_type = True +numpydoc_validate = True +numpydoc_validation_checks = { + "GL06", # Found unknown section + "GL07", # Sections are in the wrong order. + "GL09", # Deprecation warning should precede extended summary + "GL10", # reST directives {directives} must be followed by two colons + "SS01", # No summary found + "SS02", # Summary does not start with a capital letter + "SS04", # Summary contains heading whitespaces + "RT02", # The first line of the Returns section should contain only the type +} + +suppress_warnings = ["config.cache"] + +# The suffix(es) of source filenames. +source_suffix = ".rst" + +# The master toctree document. +master_doc = "index" + +# additional logos for the latex coverpage +LaTeXBuilder.supported_image_types = ["image/png", "image/pdf", "image/svg+xml"] +latex_additional_files = [watermark, ansys_logo_white, ansys_logo_white_cropped] +latex_elements = {"preamble": latex.generate_preamble(html_title)} + +# Not found page +notfound_context = { + "body": generate_404(), +} +notfound_no_urls_prefix = True + +# ONLY FOR ANSYS-SPHINX-THEME +exclude_patterns = [ + "links.rst", + "examples/sphinx-gallery/README.rst", + "examples/gallery-examples/*.ipynb", + "sg_execution_times.rst", +] +rst_epilog = "" +with Path.open(THIS_PATH / "links.rst", "r") as f: + rst_epilog += f.read() + + +linkcheck_ignore = [ + r"https://sphinxdocs.ansys.com/version/*", +] +if switcher_version != "dev": + linkcheck_ignore.append( + f"https://github.com/ansys/ansys-sphinx-theme/releases/tag/v{__version__}" + ) + + +# Configure the Jinja contexts + +jinja_contexts = { + "install_guide": { + "version": f"v{version}" if not version.endswith("dev0") else "main", + }, + "pdf_guide": {"version": get_version_match(__version__)}, # noqa: E501 +} + + +def extract_example_links( + repo_fullname: str, path_relative_to_root: str, exclude_files: List[str] = [] +) -> List[str]: + """ + Extract example links from a specific GitHub repository. + + Parameters + ---------- + repo_fullname : str + Fullname of the repository to extract example links from. + path_relative_to_root : str + Path relative to the root of the repository to extract example links from. + exclude_files : list of str + A list of files to exclude from the returned example links. + + Returns + ------- + list + List of example links. + """ + g = Github() + repo = g.get_repo(repo_fullname) + contents = repo.get_contents(path_relative_to_root) + if not isinstance(contents, list): + contents = [contents] + example_links = [] + for content in contents: + if content.type == "dir": + example_links.extend(extract_example_links(repo_fullname, content.path, exclude_files)) + elif content.type == "file": + if content.name not in exclude_files: + example_links.append(content.download_url) + + return example_links + + +def download_and_process_files(example_links: List[str]) -> List[str]: + """Download and process a series of example files. + + This function downloads a series of example files using a + list of links and processes each file. + + Parameters + ---------- + example_links : List[str] + List of links to the example files to be downloaded. + + Returns + ------- + list + List of the names of the processed files. + """ + file_names = [] + for link in example_links: + file_name = link.split("/")[-1] + file_path = str((EXAMPLE_PATH / file_name).absolute()) + with open(file_path, "wb") as f: # noqa: PTH123 + response = requests.get(link) + content = response.content.decode() + lines = content.splitlines() + # Replace the "target" string with the file name in the example files + f.write("\n".join([line.replace("target", file_name) for line in lines]).encode()) + file_names.append(file_name) + + return file_names + + +# Skip building examples if desired +BUILD_EXAMPLES = True if os.environ.get("BUILD_EXAMPLES", "true") == "true" else False +jinja_contexts["main_toctree"] = {"build_examples": BUILD_EXAMPLES} + +if not BUILD_EXAMPLES: + exclude_patterns.extend(["examples.rst", "examples/**", "examples/api/**"]) + + +else: + # Autoapi examples + extensions.append("ansys_sphinx_theme.extension.autoapi") + html_theme_options["ansys_sphinx_theme_autoapi"] = { + "project": project, + "directory": "src/ansys_sphinx_theme/examples", + "output": "examples/api", + "own_page_level": "function", + "package_depth": 1, + } + + # Gallery of examples + extensions.extend(["nbsphinx", "sphinx_gallery.gen_gallery"]) + sphinx_gallery_conf = { + # path to your examples scripts + "examples_dirs": ["examples/sphinx-gallery"], + # path where to save gallery generated examples + "gallery_dirs": ["examples/gallery-examples"], + # Pattern to search for example files + "filename_pattern": r"sphinx_gallery\.py", + # Remove the "Download all examples" button from the top level gallery + "download_all_examples": False, + # Modules for which function level galleries are created. In + "image_scrapers": ("pyvista", "matplotlib"), + "default_thumb_file": "source/_static/pyansys_light_square.png", + } + + nbsphinx_prolog = """ +Download this example as a :download:`Jupyter notebook `. + +---- +""" + nbsphinx_execute = "always" + nbsphinx_thumbnails = { + "examples/nbsphinx/jupyter-notebook": "_static/pyansys_light_square.png", + } + + pyvista.BUILDING_GALLERY = True + + # Third party examples + example_links = extract_example_links( + "executablebooks/sphinx-design", + "docs/snippets/rst", + exclude_files=["article-info.txt"], + ) + file_names = download_and_process_files(example_links) + + admonitions_links = extract_example_links( + "pydata/pydata-sphinx-theme", + "docs/examples/kitchen-sink/admonitions.rst", + ) + + admonitions_links = download_and_process_files(admonitions_links) + todo_include_todos = True # admonition todo needs this to be True + + jinja_contexts["examples"] = {"inputs_examples": file_names} + jinja_contexts["admonitions"] = {"inputs_admonitions": admonitions_links} diff --git a/doc/source/whatsnew.yml b/doc/source/whatsnew.yml index 74e1ba246..7d112d5f8 100644 --- a/doc/source/whatsnew.yml +++ b/doc/source/whatsnew.yml @@ -1,66 +1,104 @@ -fragments: -- title: Launch GUI - version: 1.2.1 - content: | - Open the current project with Mechanical GUI. - - .. code-block:: python - - from ansys.mechanical.core import App - - app = App() - app.save() - app.launch_gui() - - The above code opens up the *temporarily* saved ``.mechdb`` or `.mechdat` files. - The files are **deleted** when the ``GUI`` is closed. For more information, check the - content ``before`` `launch_gui() `_ function `another link `_ more `words`. - - Opens up the specified project file. - - .. sourcecode:: python - - launch_gui("path/to/project.mechdb") - -- title: Print Mechanical tree - version: 0.16.6 - content: | - This feature lets you see the hierarchical Mechanical project tree. - It also shows whether an object is suppressed or not. - - .. code:: - - import ansys.mechanical.core as mech - - app = mech.App() - app.update_globals(globals()) - app.print_tree() - - .. code:: shell - - ... ├── Project - ... | ├── Model - ... | | ├── Geometry Imports - ... | | ├── Geometry - ... | | ├── Materials - ... | | ├── Coordinate Systems - ... | | | ├── Global Coordinate System - ... | | ├── Remote Points - ... | | ├── Mesh - -- title: Visualize geometry in 3D - version: 0.16.3 - content: | - Visualize imported geometry in 3D. This feature is available only from 24R1 or later. - - .. code:: python - - import ansys.mechanical.core as mech - - app = mech.App(version=242) - app.update_globals(globals()) - - # Import the geometry - - # visualize - app.plot() \ No newline at end of file +fragments: +- title: Launch GUI + version: 1.2.1 + content: | + Open the current project with Mechanical GUI. + + .. code-block:: python + + from ansys.mechanical.core import App + + app = App() + app.save() + app.launch_gui() + + The above code opens up the *temporarily* saved ``.mechdb`` or `.mechdat` files. + The files are **deleted** when the ``GUI`` is closed. For more information, check the + content ``before`` `launch_gui() `_ function `another link `_ more `words`. + + Opens up the specified project file. + + .. sourcecode:: python + + launch_gui("path/to/project.mechdb") + +- title: Print Mechanical tree + version: 1.2.0 + content: | + This feature allows you to see the hierarchical Mechanical project tree. + It also shows whether an object is suppressed or not. + + .. code:: + + import ansys.mechanical.core as mech + + app = mech.App() + app.update_globals(globals()) + app.print_tree() + + .. code:: shell + + ... ├── Project + ... | ├── Model + ... | | ├── Geometry Imports + ... | | ├── Geometry + ... | | ├── Materials + ... | | ├── Coordinate Systems + ... | | | ├── Global Coordinate System + ... | | ├── Remote Points + ... | | ├── Mesh + +- title: Visualize geometry in 3D + version: 1.2.3 + content: | + Visualize imported geometry in 3D. This feature is available only from 24R1 or later. + + .. code:: python + + import ansys.mechanical.core as mech + + app = mech.App(version=242) + app.update_globals(globals()) + + # Import the geometry + + # visualize + app.plot() + +- title: title 1 + version: 1.0.7 + content: | + Title 1 content. + + .. code-block:: python + + print("title 1") + print("content") + + Paragraph paragraph + + .. sourcecode:: python + + launch_gui("path/to/project.mechdb") + +- title: title 2 + version: 1.0.4 + content: | + Title 2 sample content. + + .. code:: + + print("hello") + + .. code:: shell + + echo world + +- title: title 3 + version: 0.16.5 + content: | + Print hello world. + + .. code:: python + + print("hello world") diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 1153b2f66..d1eeee2ca 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -1,1051 +1,1070 @@ -# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT -# -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -"""Module for the Ansys Sphinx theme.""" - -from itertools import islice, tee -import logging -import os -import pathlib -import re -import subprocess -from typing import Any, Dict, Iterable -import warnings - -from docutils import nodes -from sphinx import addnodes -from sphinx.application import Sphinx -import yaml - -from ansys_sphinx_theme.extension.linkcode import DOMAIN_KEYS, sphinx_linkcode_resolve -from ansys_sphinx_theme.latex import generate_404 -from ansys_sphinx_theme.search import ( - ALL_NODES, - PARAGRAPHS, - TITLES, - create_search_index, - update_search_config, -) - -try: - import importlib.metadata as importlib_metadata -except ModuleNotFoundError: # pragma: no cover - import importlib_metadata - -__version__ = importlib_metadata.version(__name__.replace(".", "-")) - - -# Declare the fundamental paths of the theme -THIS_PATH = pathlib.Path(__file__).parent.resolve() -THEME_PATH = THIS_PATH / "theme" / "ansys_sphinx_theme" -STATIC_PATH = THEME_PATH / "static" -STYLE_PATH = STATIC_PATH / "css" -JS_PATH = STATIC_PATH / "js" -CSS_PATH = STYLE_PATH / "ansys_sphinx_theme.css" -TEMPLATES_PATH = THEME_PATH / "_templates" -AUTOAPI_TEMPLATES_PATH = TEMPLATES_PATH / "autoapi" -LOGOS_PATH = STATIC_PATH / "logos" - -ANSYS_LOGO_LINK = "https://www.ansys.com/" -PYANSYS_LOGO_LINK = "https://docs.pyansys.com/" - -"""Semantic version regex as found on semver.org: -https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string""" -SEMVER_REGEX = ( - r"(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)" - r"(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)" - r"(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?" - r"(?:\+(>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?" -) - -# make logo paths available -ansys_favicon = str((LOGOS_PATH / "ansys-favicon.png").absolute()) -ansys_logo_black = str((LOGOS_PATH / "ansys_logo_black_cropped.jpg").absolute()) -ansys_logo_white = str((LOGOS_PATH / "ansys_logo_white.pdf").absolute()) -ansys_logo_white_cropped = str((LOGOS_PATH / "ansys_logo_white_cropped.pdf").absolute()) -page_404 = str((STATIC_PATH / "404.rst").absolute()) -pyansys_logo_black = str((LOGOS_PATH / "pyansys-logo-black-cropped.png").absolute()) -pyansys_logo_white = str((LOGOS_PATH / "pyansys-logo-white-cropped.png").absolute()) -watermark = str((LOGOS_PATH / "watermark.pdf").absolute()) -pyansys_logo_dark_mode = str((LOGOS_PATH / "pyansys_logo_transparent_white.png").absolute()) -pyansys_logo_light_mode = str((LOGOS_PATH / "pyansys_logo_transparent_black.png").absolute()) -ansys_logo_light_mode = str((LOGOS_PATH / "ansys_logo_transparent_black.png").absolute()) -ansys_logo_dark_mode = str((LOGOS_PATH / "ansys_logo_transparent_white.png").absolute()) - -# Cheat sheet extension version -CHEAT_SHEET_QUARTO_EXTENTION_VERSION = "v1" - - -def get_html_theme_path() -> pathlib.Path: - """Return list of HTML theme paths. - - Returns - ------- - pathlib.Path - Path pointing to the installation directory of the theme. - - """ - return THEME_PATH.resolve() - - -def get_autoapi_templates_dir_relative_path(path: pathlib.Path) -> str: - """Return a string representing the relative path for autoapi templates. - - Parameters - ---------- - path : pathlib.Path - Path to the desired file. - - Returns - ------- - str - A string rerpesenting the relative path to the autoapi templates. - - """ - return os.path.relpath(str(AUTOAPI_TEMPLATES_PATH.absolute()), start=str(path.absolute())) - - -def get_version_match(semver: str) -> str: - """Evaluate the version match for the multi-documentation. - - Parameters - ---------- - semver : str - Semantic version number in the form of a string. - - Returns - ------- - str - Matching version number in the form of a string. - - """ - if "dev" in semver: - return "dev" - major, minor, *_ = semver.split(".") - return ".".join([major, minor]) - - -def setup_default_html_theme_options(app): - """Set up the default configuration for the HTML options. - - Parameters - ---------- - app : ~sphinx.application.Sphinx - Application instance for rendering the documentation. - - Notes - ----- - This function is the only way to overwrite ``pydata-sphinx-theme`` - configuration. Variables declared in the ``theme.conf`` do not include - inherited ones. - - """ - # Place all switchers and icons at the end of the navigation bar - theme_options = app.config.html_theme_options - # Place all switchers and icons at the end of the navigation bar - if theme_options.get("switcher"): - theme_options.setdefault( - "navbar_end", ["version-switcher", "theme-switcher", "navbar-icon-links"] - ) - theme_options.setdefault("collapse_navigation", True) - theme_options.setdefault("navigation_with_keys", True) - - # Update the icon links. If not given, add a default GitHub icon. - if not theme_options.get("icon_links") and theme_options.get("github_url"): - theme_options["icon_links"] = [ - { - "name": "GitHub", - "url": theme_options["github_url"], - "icon": "fa-brands fa-github", - } - ] - theme_options["github_url"] = None - - # Add default pygments style options - if not theme_options.get("pygments_light_style"): - theme_options["pygments_light_style"] = "friendly" - if not theme_options.get("pygments_dark_style"): - theme_options["pygments_dark_style"] = "monokai" - - -def fix_toctree( - app: Sphinx, pagename: str, templatename: str, context: Dict[str, Any], doctree: nodes.document -): - """Add the what's new content to the html page.""" - from bs4 import BeautifulSoup - - if "changelog" in pagename: - # body = context.get("body", "") - toc = context.get("toc", "") - - # Update toctree with minor & what's new sections - print(toc) - - # body = BeautifulSoup(body, 'html.parser') - # # print(soup.prettify()) - # for section in body.find_all('section'): - # # release_notes_title = section.find('h1') - # # print(release_notes_title) - # for h2 in section.find_all('h2'): - # patch_version = re.search(SEMVER_REGEX, h2.text) - # if patch_version: - # # Create the minor version from the patch version - # minor_version = ".".join(patch_version.groups()[:2]) - # if minor_version not in minor_versions: - # minor_versions.append(minor_version) - # minor_version = ".".join(patch_version.groups()[:2]) - - # h2.name = "h3" - - # minor_version_title = body.new_tag("h2", id=f"version-{minor_version}") - # minor_version_title.string = f"Version {minor_version}" - - # # if release_notes_title != None: - # # release_notes_title.append(minor_version_title) - # # else: - # h2.parent.append(minor_version_title) - # # print(h2.parent) - # # print(h2) - # # print("") - # else: - # h2.name = "h3" - - # context["body"] = body - - -def fix_edit_html_page_context( - app: Sphinx, pagename: str, templatename: str, context: dict, doctree: nodes.document -) -> None: - """Add a function that Jinja can access for returning an "edit this page" link . - - This function creates an "edit this page" link for any library. - The link points to the corresponding file on the main branch. - - Parameters - ---------- - app : Sphinx - Sphinx application instance for rendering the documentation. - pagename : str - Name of the current page. - templatename : str - Name of the template being used. - context : dict - Context dictionary for the page. - doctree : document - Document tree for the page. - - Notes - ----- - [1] Originally implemented by `Alex Kaszynski `_ in - `PyVista `_ , - see https://github.com/pyvista/pyvista/pull/4113 - """ - - def fix_edit_link_page(link: str) -> str: - """Transform "edit on GitHub" links to the correct URL. - - This function fixes the URL for the "edit this page" link. - - Parameters - ---------- - link : str - Link to the GitHub edit interface. - - Returns - ------- - str - Link to the corresponding file on the main branch. - """ - github_user = context.get("github_user", "") - github_repo = context.get("github_repo", "") - github_source = context.get("source_path", "") - kind = context.get("github_version", "") - - if "_autosummary" in pagename: - for obj_node in list(doctree.findall(addnodes.desc)): - try: - domain = obj_node.get("domain") - for signode in obj_node: - if not isinstance(signode, addnodes.desc_signature): - continue - # Convert signode to a specified format - info = {} - for key in DOMAIN_KEYS.get(domain, []): - value = signode.get(key) - if not value: - value = "" - info[key] = value - if not info: - continue - # This is an API example - return sphinx_linkcode_resolve( - domain=domain, - info=info, - library=f"{github_user}/{github_repo}", - source_path=github_source, - github_version=kind, - edit=True, - ) - except ValueError as e: - logging.debug(f"An error occurred: {e}") # Log the exception as debug info - return link - - elif "api" in pagename: - for obj_node in list(doctree.findall(addnodes.desc)): - domain = obj_node.get("domain") - if domain != "py": - return link - - for signode in obj_node: - if not isinstance(signode, addnodes.desc_signature): - continue - - fullname = signode["fullname"] - modname = fullname.replace(".", "/") - - if github_source: - return f"http://github.com/{github_user}/{github_repo}/edit/{kind}/{github_source}/{modname}.{domain}" # noqa: E501 - else: - return f"http://github.com/{github_user}/{github_repo}/edit/{kind}/{modname}.{domain}" # noqa: E501 - - else: - return link - - context["fix_edit_link_page"] = fix_edit_link_page - - -def update_footer_theme( - app: Sphinx, pagename: str, templatename: str, context: Dict[str, Any], doctree: nodes.document -) -> None: - """Update the version number of the Ansys Sphinx theme in the footer. - - Connect to the Sphinx application instance for rendering the documentation, - and add the current version number of the Ansys Sphinx theme to the page context. - This allows the theme to update the footer with the current version number. - - Parameters - ---------- - app : ~sphinx.application.Sphinx - Application instance for rendering the documentation. - pagename : str - The name of the current page. - templatename : str - The name of the template being used. - context : dict - The context dictionary for the page. - doctree : ~docutils.nodes.document - The document tree for the page. - """ - context["ansys_sphinx_theme_version"] = __version__ - - -def replace_html_tag(app, exception): - """Replace HTML tags in the generated HTML files. - - Parameters - ---------- - app : ~sphinx.application.Sphinx - Application instance for rendering the documentation. - exception : Exception - Exception that occurred during the build process. - """ - if exception is not None: - return - - build_dir = pathlib.Path(app.builder.outdir).resolve() - defined_extensions = app.config["extensions"] - if not any( - extension in defined_extensions - for extension in ["autoapi.extension", "ansys_sphinx_theme.extension.autoapi"] - ): - return - api_dir = app.config["autoapi_root"] - api_path = build_dir / api_dir - if not api_path.exists(): - return - - file_names = list(api_path.rglob("*.html")) - for file_name in file_names: - with pathlib.Path.open(api_dir / file_name, "r", encoding="utf-8") as file: - content = file.read() - with pathlib.Path.open(api_dir / file_name, "w", encoding="utf-8") as file: - modified_content = content.replace("<", "<").replace(">", ">") - file.write(modified_content) - - -def configure_theme_logo(app: Sphinx): - """ - Configure the theme logo based on the theme options. - - Parameters - ---------- - app : sphinx.application.Sphinx - Application instance for rendering the documentation. - """ - # Define logo configurations - pyansys_logo = { - "image_dark": pyansys_logo_dark_mode, - "image_light": pyansys_logo_light_mode, - } - - ansys_logo = { - "image_dark": ansys_logo_dark_mode, - "image_light": ansys_logo_light_mode, - } - theme_options = app.config.html_theme_options - logo_option = theme_options.get("logo") - - if not logo_option: - theme_options["logo"] = pyansys_logo - - if isinstance(logo_option, str) and logo_option not in {"ansys", "pyansys", "no_logo"}: - raise ValueError( - f"Invalid logo option: '{logo_option}'. The logo option must be either 'ansys', 'pyansys', or 'no_logo'" # noqa: E501 - ) - - if logo_option == "ansys": - theme_options["logo"] = ansys_logo - theme_options["logo_link"] = theme_options.get("logo_link", ANSYS_LOGO_LINK) - elif logo_option == "pyansys": - theme_options["logo"] = pyansys_logo - theme_options["logo_link"] = theme_options.get("logo_link", PYANSYS_LOGO_LINK) - elif logo_option == "no_logo": - theme_options["logo"] = None - - elif isinstance(logo_option, dict): - theme_options["logo"] = logo_option - - -def convert_pdf_to_png(pdf_path: pathlib.Path, output_dir: pathlib.Path, output_png: str): - """ - Convert PDF to PNG images. - - Parameters - ---------- - pdf_path : pathlib.Path - Path to the PDF file. - output_dir : pathlib.Path - Path to the output directory. - output_png : str - Name of the output PNG file. - """ - try: - from pdf2image import convert_from_path - except ImportError as e: - raise ImportError( - f"Failed to import `pdf2image`: {e}. Install the package using `pip install pdf2image`" # noqa: E501 - ) - try: - images = convert_from_path(pdf_path, 500) - images[0].save(output_dir / output_png, "PNG") - except Exception as e: - raise RuntimeError( - f"Failed to convert PDF to PNG: {e}, ensure `poppler` is installed. See https://pypi.org/project/pdf2image/" # noqa: E501 - ) - - -def add_cheat_sheet( - app: Sphinx, pagename: str, templatename: str, context: Dict[str, Any], doctree: nodes.document -) -> None: - """Add a cheat sheet to the left navigation sidebar. - - Parameters - ---------- - app : ~sphinx.application.Sphinx - Application instance for rendering the documentation. - pagename : str - Name of the current page. - templatename : str - Name of the template being used. - context : dict - Context dictionary for the page. - doctree : ~docutils.nodes.document - The doctree. - """ - cheatsheet_options = app.config.html_theme_options.get("cheatsheet", {}) - pages = cheatsheet_options.get("pages", ["index"]) - pages = [pages] if isinstance(pages, str) else pages - if cheatsheet_options and any(pagename == page for page in pages): - sidebar = context.get("sidebars", []) - sidebar.append("cheatsheet_sidebar.html") - context["sidebars"] = sidebar - - -def build_quarto_cheatsheet(app: Sphinx): - """ - Build the Quarto cheatsheet. - - Parameters - ---------- - app : sphinx.application.Sphinx - Application instance for rendering the documentation. - """ - cheatsheet_options = app.config.html_theme_options.get("cheatsheet", {}) - - if not cheatsheet_options: - return - - cheatsheet_file = cheatsheet_options.get("file", "") - output_dir = "_static" - version = cheatsheet_options.get("version", "main") - - if not cheatsheet_file: - return - - cheatsheet_file = pathlib.Path(app.srcdir) / cheatsheet_file - file_name = str(cheatsheet_file.name) - file_path = cheatsheet_file.parent - output_dir_path = pathlib.Path(app.outdir) / output_dir - try: - # Add the cheatsheet to the Quarto project - subprocess.run( - [ - "quarto", - "add", - f"ansys/pyansys-quarto-cheatsheet@{CHEAT_SHEET_QUARTO_EXTENTION_VERSION}", - "--no-prompt", - ], - cwd=file_path, - capture_output=True, - text=True, - ) - - # Render the cheatsheet - subprocess.run( - [ - "quarto", - "render", - file_name, - "--to", - "cheat_sheet-pdf", - "--output-dir", - output_dir_path, - "-V", - f"version={version}", - ], - cwd=file_path, - capture_output=True, - text=True, - ) - - # Remove the cheatsheet from the Quarto project - subprocess.run( - ["quarto", "remove", "ansys/cheat_sheet", "--no-prompt"], - cwd=file_path, - capture_output=True, - text=True, - ) - - # Remove all supplementary files - supplementary_files = [ - "_static/slash.png", - "_static/bground.png", - "_static/ansys.png", - ] - for file in supplementary_files: - file_path = cheatsheet_file.parent / file - if file_path.exists(): - file_path.unlink() - - # If static folder is clean, delete it - if not list(cheatsheet_file.parent.glob("_static/*")): - cheatsheet_file.parent.joinpath("_static").rmdir() - - except subprocess.CalledProcessError as e: - raise RuntimeError(f"Failed to build Quarto cheatsheet: {e}. Ensure Quarto is installed.") - - output_file = output_dir_path / file_name.replace(".qmd", ".pdf") - app.config.html_theme_options["cheatsheet"]["output_dir"] = f"{output_dir}/{output_file.name}" - output_png = file_name.replace(".qmd", ".png") - convert_pdf_to_png(output_file, output_dir_path, output_png) - app.config.html_theme_options["cheatsheet"]["thumbnail"] = f"{output_dir}/{output_png}" - - -def check_for_depreciated_theme_options(app: Sphinx): - """Check for depreciated theme options. - - Parameters - ---------- - app : sphinx.application.Sphinx - Application instance for rendering the documentation. - """ - theme_options = app.config.html_theme_options - if "use_meilisearch" in theme_options: - warnings.warn( - "The 'use_meilisearch' option is deprecated. Remove the option " - "from your configuration file.", - DeprecationWarning, - ) - - -def retrieve_whatsnew_input(app: Sphinx): - config_options = app.config.html_theme_options - - whats_new_options = config_options.get("whatsnew") - if not whats_new_options: - return - - no_of_contents = whats_new_options.get("no_of_headers", 3) - whatsnew_file = whats_new_options.get("whatsnew_file", "whatsnew") # .yml - changelog_file = whats_new_options.get("changelog_file", "changelog") # .rst - - return no_of_contents, whatsnew_file, changelog_file - - -def add_whatsnew_changelog(app, doctree): - """Create doctree with minor version and what's new content.""" - no_of_contents, whatsnew_file, changelog_file = retrieve_whatsnew_input(app) - # Read the file and get the sections from the file as a list. For example, - # sections = [
      ] - sections = doctree.traverse(nodes.document) - if not sections: - return - - # The source directory of the documentation: {repository_root}/doc/source - src_files = app.env.srcdir - changelog_file = pathlib.Path(src_files) / f"{changelog_file}.rst" - - # Get the file name of the section using section.get("source") and return the section - # if section.get("source") is equal to the changelog_file - changelog_doctree_sections = [ - section for section in sections if section.get("source") == str(changelog_file) - ] - - # Return if the changelog file sections are not found - if not changelog_doctree_sections: - return - - # Open what's new yaml file, load the data, and get the minor versions - whatsnew_file = pathlib.Path(src_files) / f"{whatsnew_file}.yml" - if whatsnew_file.exists(): - with pathlib.Path.open(whatsnew_file, "r", encoding="utf-8") as file: - whatsnew_data = yaml.safe_load(file) - - whatsnew_minor_versions = set() - for fragment in whatsnew_data["fragments"]: - yaml_minor_version = ".".join(fragment["version"].split(".")[:2]) - whatsnew_minor_versions.add(yaml_minor_version) - - # to do: get the version from the config, also get patch and minor version - minor_version = get_version_match(app.env.config.version) - patch_version = app.env.config.version.split(".")[2] - - existing_minor_versions = [] - docs_content = doctree.traverse(nodes.section) - for node in docs_content: - # Get the content of the next node - next_node = node.next_node(nodes.reference) - # Get the name of the next node - section_name = next_node.get("name") - if section_name: - # Get the patch version from the section name - patch_version = re.search(SEMVER_REGEX, section_name) - if patch_version: - # Create the minor version from the patch version - minor_version = ".".join(patch_version.groups()[:2]) - if minor_version not in existing_minor_versions: - # Add minor version to list of existing minor versions - existing_minor_versions.append(minor_version) - - # Create a section for the minor version - minor_version_section = nodes.section( - ids=[f"version-{minor_version}"], names=[f"Version {minor_version}"] - ) - # Add the title to the section for the minor version - minor_version_section += nodes.title("", f"Version {minor_version}") - - # Add "What's New" section under the minor version if the minor version is in - # the what's new data - if whatsnew_file.exists() and (minor_version in whatsnew_minor_versions): - minor_version_whatsnew = add_whatsnew_to_minor_version( - minor_version, whatsnew_data - ) - minor_version_section.append(minor_version_whatsnew) - - # Insert the minor_version_section into the node - if "release notes" in node[0].astext().lower(): - # Add the title with the minor version after "Release Notes" - node.insert(1, minor_version_section) - else: - # Add the title at the beginning of a section with a patch version - node.insert(0, minor_version_section) - - # print(doctree) - - -def add_whatsnew_to_minor_version(minor_version, whatsnew_data): - """Add the what's new title and content under the minor version.""" - # Add the what's new section and title - minor_version_whatsnew = nodes.section( - ids=[f"version-{minor_version}-whatsnew"], names=["What's New"] - ) - minor_version_whatsnew += nodes.title("", "What's New") - - # Add a dropdown under the "What's New" section for each fragment in the whatsnew.yml file - for fragment in whatsnew_data["fragments"]: - if minor_version in fragment["version"]: - whatsnew_dropdown = nodes.container( - body_classes=[""], - chevron=True, - container_classes=["sd-mb-3 sd-fade-in-slide-down"], - design_component="dropdown", - has_title=True, - icon="", - is_div=True, - opened=False, - title_classes=[""], - type="dropdown", - ) - whatsnew_dropdown += nodes.rubric("", fragment["title"]) - - # Add a line specifying which version the fragment is available in - version_paragraph = nodes.paragraph("sd-card-text") - version_paragraph.append( - nodes.emphasis("", f"Available in v{fragment['version']} and later") - ) - whatsnew_dropdown += version_paragraph - - # Split content from YAML file into list - content_lines = fragment["content"].split("\n") - - # Create iterator for the content_lines - content_iterator = iter(content_lines) - - # Navigate to first line in the iterator - line = next(content_iterator, None) - - while line is not None: - if ".. code" in line or ".. sourcecode" in line: - # Get language after "code::" - language = line.split("::")[1].strip() - # Create the code block container node with the language if it exists - code_block = ( - nodes.container(classes=[f"highlight-{language} notranslate"]) - if language - else nodes.container() - ) - - # Fill the code block with the following lines until it reaches the end or an - # unindented line - code_block, line = fill_code_block(content_iterator, code_block) - whatsnew_dropdown += code_block - else: - # Create the paragraph node - paragraph = nodes.paragraph("sd-card-text") - - # Fill the paragraph node with the following lines until it reaches - # the end or a code block - paragraph, line = fill_paragraph(content_iterator, paragraph, line) - whatsnew_dropdown += paragraph - - # Append the fragment dropdown to the minor_version_whatsnew section - minor_version_whatsnew.append(whatsnew_dropdown) - - return minor_version_whatsnew - - -def fill_code_block(content_iterator: Iterable, code_block: nodes.container) -> nodes.container: - """Fill the code block. - - Parameters - ---------- - content_iterator : Iterable - Iterator for the content lines from the fragments in the whatsnew.yml file. - code_block : nodes.container - Container node for the code block. - - Returns - ------- - nodes.container, str - Container node for the code block and the next line in the content iterator. - """ - # classes=["highlight"] is required for the copy button to show up in the literal_block - highlight_container = nodes.container(classes=["highlight"]) - - # Create literal block with copy button - literal_block = nodes.literal_block( - classes=["sd-button sd-button--icon sd-button--icon-only sd-button--icon-small"], - icon="copy", - label="Copy", - title="Copy", - ) - - # Move to the first line in the code block (the line after ".. code::") - next_line = next(content_iterator, None) - - # While the next_line is indented or blank, add it to the code block - while next_line is not None and (next_line.startswith(" ") or (next_line == "")): - formatted_line = next_line.lstrip() + "\n" - # Add the formatted line to the literal block - literal_block += nodes.inline(text=formatted_line) - - # Break the loop if the end of the content is reached - if next_line is not None: - # Move to the next line in the content - next_line = next(content_iterator, None) - else: - break - - # Add the literal block to the highlight container - highlight_container += literal_block - - # Add the highlight container to the code block - code_block += highlight_container - - return code_block, next_line - - -def fill_paragraph( - content_iterator: Iterable, paragraph: nodes.paragraph, next_line: str -) -> nodes.paragraph: - """Fill the paragraph node. - - Parameters - ---------- - content_iterator : Iterable - Iterator for the content lines from the fragments in the whatsnew.yml file. - paragraph : nodes.paragraph - Paragraph node. - next_line : str - Next line in the content iterator. - - Returns - ------- - nodes.paragraph, str - Paragraph node and the next line in the content iterator. - """ - # While the next_line is not None and is not a code block, add it to the paragraph - while next_line is not None and not next_line.startswith(".. "): - # Regular expressions to find rst links, and single & double backticks/asterisks - rst_link_regex = r"(`[^<`]+? <[^>`]+?>`_)" - single_backtick_regex = r"(`[^`]+?`)" - double_backtick_regex = r"(``.*?``)" - bold_text_regex = r"(\*\*.*?\*\*)" - italic_text_regex = r"(\*[^\*]+?\*)" - - # Check if there are rst links, single & double backticks/asterisks in the line - link_backtick_regex = ( - rf"{rst_link_regex}|" - rf"{single_backtick_regex}|{double_backtick_regex}|" - rf"{bold_text_regex}|{italic_text_regex}" - ) - - # Get all matches for rst links, single & double backticks/asterisks in the line - # Sample: next_line = "The files are **deleted** when the ``GUI`` is closed. For more info" - # For example, matches = [('', '', '', '**deleted**', ''), ('', '', '``GUI``', '', '')] - matches = re.findall(link_backtick_regex, next_line) - - if matches: - # Get all of the matches from the matches list - # For example, regex_matches = ['**deleted**', '``GUI``'] - regex_matches = [ - element for match in matches for i, element in enumerate(match) if element - ] - - # Create a regular expression pattern that matches any URL - # For example, pattern = r"\*\*deleted\*\*|``GUI``" - pattern = "|".join(map(re.escape, regex_matches)) - - # Split the line using the pattern - # For example, split_lines = ['The files are ', '**deleted**', ' when the ', '``GUI``', - # ' is closed. For more info'] - split_lines = re.split(f"({pattern})", next_line) - - for line in split_lines: - if line in regex_matches: - # If it matches RST link regex, append a reference node - if re.search(rst_link_regex, line): - text, url = re.findall(r"`([^<`]+?) <([^>`]+?)>`_", line)[0] - if url.startswith("http") or url.startswith("www"): - ref_type = "external" - else: - ref_type = "internal" - paragraph.append( - nodes.reference( - classes=[f"reference-{ref_type}"], - refuri=url, - href=url, - text=text, - ) - ) - # If it matches single or double backticks, append a literal node - elif re.search(single_backtick_regex, line): - text = re.findall(r"`([^`]+?)`", line)[0] - paragraph.append(nodes.literal(text=text)) - elif re.search(double_backtick_regex, line): - text = re.findall(r"``(.*?)``", line)[0] - paragraph.append(nodes.literal(text=text)) - # If it matches bold text, append a strong node - elif re.search(bold_text_regex, line): - text = re.findall(r"\*\*(.*?)\*\*", line)[0] - paragraph.append(nodes.strong(text=text)) - # If it matches italic text, append an emphasis node - elif re.search(italic_text_regex, line): - text = re.findall(r"\*([^\*]+?)\*", line)[0] - paragraph.append(nodes.emphasis(text=text)) - else: - paragraph.append(nodes.inline(text=line)) - else: - # Append the next_line as an inline element, unless it is an empty string. If it's an - # empty string, append a line break - paragraph.append(nodes.inline(text=next_line)) if next_line != "" else paragraph.append( - nodes.line(text="\n") - ) - - # Add a space at the end of each line - paragraph.append(nodes.inline(text=" ")) - - # Break the loop if the end of the content is reached - if next_line is not None: - # Move to the next line in the content - next_line = next(content_iterator, None) - else: - break - - return paragraph, next_line - - -def extract_whatsnew(app, doctree, docname): - """Extract the what's new content from the document.""" - no_of_contents, whatsnew_file, changelog_file = retrieve_whatsnew_input(app) - - # Extract the what's new content from the changelog file - doctree = app.env.get_doctree(changelog_file) - whatsnew = [] - docs_content = doctree.traverse(nodes.section) - app.env.whatsnew = [] - - if not docs_content: - return - - versions_nodes = [node for node in docs_content if node.get("ids")[0].startswith("version")] - - # get the version nodes upto the specified number of headers - versions_nodes = versions_nodes[:no_of_contents] - - if not versions_nodes: - return - - for version_node in versions_nodes: - title = version_node[0].astext() - sections = list(version_node.traverse(nodes.section)) - - whatsnew_nodes = [node for node in sections if node[0].astext().lower() == "whatsnew"] - - if not whatsnew_nodes: - continue - - children = [node for node in whatsnew_nodes[0].traverse(nodes.section)] - - headers = [child[0].astext() for child in children] - - if len(children) > 1: - children = headers[1:] - else: - children = [whatsnew_nodes[0].traverse(nodes.paragraph)[0].astext()] - - contents = { - "title": title, - "title_url": f"{changelog_file}.html#{version_node.get('ids')[0]}", - "children": children, - "url": f"{changelog_file}.html#{whatsnew_nodes[0]['ids'][0]}", - } - - whatsnew.append(contents) - - app.env.whatsnew = whatsnew - - -def add_whatsnew_sidebar(app, pagename, templatename, context, doctree): - """Add what's new section to the context.""" - config_options = app.config.html_theme_options - whats_new_options = config_options.get("whatsnew") - if not whats_new_options: - return - - pages = whats_new_options.get("pages", ["index"]) - if pagename not in pages: - return - - whatsnew = context.get("whatsnew", []) - whatsnew.extend(app.env.whatsnew) - context["whatsnew"] = whatsnew - sidebar = context.get("sidebars", []) - sidebar.append("whatsnew_sidebar.html") - context["sidebars"] = sidebar - - -def setup(app: Sphinx) -> Dict: - """Connect to the Sphinx theme app. - - Parameters - ---------- - app : ~sphinx.application.Sphinx - Application instance for rendering the documentation. - - Returns - ------- - Dict - Dictionary containing application status. - - """ - # Add the theme configuration - theme_path = get_html_theme_path() - app.add_html_theme("ansys_sphinx_theme", theme_path) - app.config.templates_path.append(str(THEME_PATH / "components")) - - # Add default HTML configuration - setup_default_html_theme_options(app) - - use_ansys_search = app.config.html_theme_options.get("use_ansys_search", True) - if use_ansys_search: - update_search_config(app) - - # Verify that the main CSS file exists - if not CSS_PATH.exists(): - raise FileNotFoundError(f"Unable to locate ansys-sphinx theme at {CSS_PATH.absolute()}") - app.add_css_file(str(CSS_PATH.relative_to(STATIC_PATH))) - app.config.templates_path.append(str(TEMPLATES_PATH)) - app.add_js_file("https://cdn.datatables.net/1.10.23/js/jquery.dataTables.min.js") - app.add_css_file("https://cdn.datatables.net/1.10.23/css/jquery.dataTables.min.css") - app.add_css_file("https://www.nerdfonts.com/assets/css/webfont.css") - app.connect("builder-inited", configure_theme_logo) - app.connect("builder-inited", build_quarto_cheatsheet) - app.connect("builder-inited", check_for_depreciated_theme_options) - app.connect("doctree-read", add_whatsnew_changelog) - app.connect("doctree-resolved", extract_whatsnew) - app.connect("html-page-context", add_whatsnew_sidebar) - app.connect("html-page-context", update_footer_theme) - app.connect("html-page-context", fix_edit_html_page_context) - # app.connect("html-page-context", fix_toctree) - app.connect("html-page-context", add_cheat_sheet) - app.connect("build-finished", replace_html_tag) - if use_ansys_search: - app.connect("build-finished", create_search_index) - return { - "version": __version__, - "parallel_read_safe": True, - "parallel_write_safe": True, - } - - -__all__ = ["__version__", "generate_404", "get_version_match", "TITLES", "PARAGRAPHS", "ALL_NODES"] +# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""Module for the Ansys Sphinx theme.""" + +from itertools import islice, tee +import logging +import os +import pathlib +import re +import subprocess +from typing import Any, Dict, Iterable +import warnings + +from docutils import nodes +from sphinx import addnodes +from sphinx.application import Sphinx +import yaml + +from ansys_sphinx_theme.extension.linkcode import DOMAIN_KEYS, sphinx_linkcode_resolve +from ansys_sphinx_theme.latex import generate_404 +from ansys_sphinx_theme.search import ( + ALL_NODES, + PARAGRAPHS, + TITLES, + create_search_index, + update_search_config, +) + +try: + import importlib.metadata as importlib_metadata +except ModuleNotFoundError: # pragma: no cover + import importlib_metadata + +__version__ = importlib_metadata.version(__name__.replace(".", "-")) + + +# Declare the fundamental paths of the theme +THIS_PATH = pathlib.Path(__file__).parent.resolve() +THEME_PATH = THIS_PATH / "theme" / "ansys_sphinx_theme" +STATIC_PATH = THEME_PATH / "static" +STYLE_PATH = STATIC_PATH / "css" +JS_PATH = STATIC_PATH / "js" +CSS_PATH = STYLE_PATH / "ansys_sphinx_theme.css" +TEMPLATES_PATH = THEME_PATH / "_templates" +AUTOAPI_TEMPLATES_PATH = TEMPLATES_PATH / "autoapi" +LOGOS_PATH = STATIC_PATH / "logos" + +ANSYS_LOGO_LINK = "https://www.ansys.com/" +PYANSYS_LOGO_LINK = "https://docs.pyansys.com/" + +"""Semantic version regex as found on semver.org: +https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string""" +SEMVER_REGEX = ( + r"(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)" + r"(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)" + r"(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?" + r"(?:\+(>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?" +) + +# make logo paths available +ansys_favicon = str((LOGOS_PATH / "ansys-favicon.png").absolute()) +ansys_logo_black = str((LOGOS_PATH / "ansys_logo_black_cropped.jpg").absolute()) +ansys_logo_white = str((LOGOS_PATH / "ansys_logo_white.pdf").absolute()) +ansys_logo_white_cropped = str((LOGOS_PATH / "ansys_logo_white_cropped.pdf").absolute()) +page_404 = str((STATIC_PATH / "404.rst").absolute()) +pyansys_logo_black = str((LOGOS_PATH / "pyansys-logo-black-cropped.png").absolute()) +pyansys_logo_white = str((LOGOS_PATH / "pyansys-logo-white-cropped.png").absolute()) +watermark = str((LOGOS_PATH / "watermark.pdf").absolute()) +pyansys_logo_dark_mode = str((LOGOS_PATH / "pyansys_logo_transparent_white.png").absolute()) +pyansys_logo_light_mode = str((LOGOS_PATH / "pyansys_logo_transparent_black.png").absolute()) +ansys_logo_light_mode = str((LOGOS_PATH / "ansys_logo_transparent_black.png").absolute()) +ansys_logo_dark_mode = str((LOGOS_PATH / "ansys_logo_transparent_white.png").absolute()) + +# Cheat sheet extension version +CHEAT_SHEET_QUARTO_EXTENTION_VERSION = "v1" + + +def get_html_theme_path() -> pathlib.Path: + """Return list of HTML theme paths. + + Returns + ------- + pathlib.Path + Path pointing to the installation directory of the theme. + + """ + return THEME_PATH.resolve() + + +def get_autoapi_templates_dir_relative_path(path: pathlib.Path) -> str: + """Return a string representing the relative path for autoapi templates. + + Parameters + ---------- + path : pathlib.Path + Path to the desired file. + + Returns + ------- + str + A string rerpesenting the relative path to the autoapi templates. + + """ + return os.path.relpath(str(AUTOAPI_TEMPLATES_PATH.absolute()), start=str(path.absolute())) + + +def get_version_match(semver: str) -> str: + """Evaluate the version match for the multi-documentation. + + Parameters + ---------- + semver : str + Semantic version number in the form of a string. + + Returns + ------- + str + Matching version number in the form of a string. + + """ + if "dev" in semver: + return "dev" + major, minor, *_ = semver.split(".") + return ".".join([major, minor]) + + +def setup_default_html_theme_options(app): + """Set up the default configuration for the HTML options. + + Parameters + ---------- + app : ~sphinx.application.Sphinx + Application instance for rendering the documentation. + + Notes + ----- + This function is the only way to overwrite ``pydata-sphinx-theme`` + configuration. Variables declared in the ``theme.conf`` do not include + inherited ones. + + """ + # Place all switchers and icons at the end of the navigation bar + theme_options = app.config.html_theme_options + # Place all switchers and icons at the end of the navigation bar + if theme_options.get("switcher"): + theme_options.setdefault( + "navbar_end", ["version-switcher", "theme-switcher", "navbar-icon-links"] + ) + theme_options.setdefault("collapse_navigation", True) + theme_options.setdefault("navigation_with_keys", True) + + # Update the icon links. If not given, add a default GitHub icon. + if not theme_options.get("icon_links") and theme_options.get("github_url"): + theme_options["icon_links"] = [ + { + "name": "GitHub", + "url": theme_options["github_url"], + "icon": "fa-brands fa-github", + } + ] + theme_options["github_url"] = None + + # Add default pygments style options + if not theme_options.get("pygments_light_style"): + theme_options["pygments_light_style"] = "friendly" + if not theme_options.get("pygments_dark_style"): + theme_options["pygments_dark_style"] = "monokai" + + +def fix_edit_html_page_context( + app: Sphinx, pagename: str, templatename: str, context: dict, doctree: nodes.document +) -> None: + """Add a function that Jinja can access for returning an "edit this page" link . + + This function creates an "edit this page" link for any library. + The link points to the corresponding file on the main branch. + + Parameters + ---------- + app : Sphinx + Sphinx application instance for rendering the documentation. + pagename : str + Name of the current page. + templatename : str + Name of the template being used. + context : dict + Context dictionary for the page. + doctree : document + Document tree for the page. + + Notes + ----- + [1] Originally implemented by `Alex Kaszynski `_ in + `PyVista `_ , + see https://github.com/pyvista/pyvista/pull/4113 + """ + + def fix_edit_link_page(link: str) -> str: + """Transform "edit on GitHub" links to the correct URL. + + This function fixes the URL for the "edit this page" link. + + Parameters + ---------- + link : str + Link to the GitHub edit interface. + + Returns + ------- + str + Link to the corresponding file on the main branch. + """ + github_user = context.get("github_user", "") + github_repo = context.get("github_repo", "") + github_source = context.get("source_path", "") + kind = context.get("github_version", "") + + if "_autosummary" in pagename: + for obj_node in list(doctree.findall(addnodes.desc)): + try: + domain = obj_node.get("domain") + for signode in obj_node: + if not isinstance(signode, addnodes.desc_signature): + continue + # Convert signode to a specified format + info = {} + for key in DOMAIN_KEYS.get(domain, []): + value = signode.get(key) + if not value: + value = "" + info[key] = value + if not info: + continue + # This is an API example + return sphinx_linkcode_resolve( + domain=domain, + info=info, + library=f"{github_user}/{github_repo}", + source_path=github_source, + github_version=kind, + edit=True, + ) + except ValueError as e: + logging.debug(f"An error occurred: {e}") # Log the exception as debug info + return link + + elif "api" in pagename: + for obj_node in list(doctree.findall(addnodes.desc)): + domain = obj_node.get("domain") + if domain != "py": + return link + + for signode in obj_node: + if not isinstance(signode, addnodes.desc_signature): + continue + + fullname = signode["fullname"] + modname = fullname.replace(".", "/") + + if github_source: + return f"http://github.com/{github_user}/{github_repo}/edit/{kind}/{github_source}/{modname}.{domain}" # noqa: E501 + else: + return f"http://github.com/{github_user}/{github_repo}/edit/{kind}/{modname}.{domain}" # noqa: E501 + + else: + return link + + context["fix_edit_link_page"] = fix_edit_link_page + + +def update_footer_theme( + app: Sphinx, pagename: str, templatename: str, context: Dict[str, Any], doctree: nodes.document +) -> None: + """Update the version number of the Ansys Sphinx theme in the footer. + + Connect to the Sphinx application instance for rendering the documentation, + and add the current version number of the Ansys Sphinx theme to the page context. + This allows the theme to update the footer with the current version number. + + Parameters + ---------- + app : ~sphinx.application.Sphinx + Application instance for rendering the documentation. + pagename : str + The name of the current page. + templatename : str + The name of the template being used. + context : dict + The context dictionary for the page. + doctree : ~docutils.nodes.document + The document tree for the page. + """ + context["ansys_sphinx_theme_version"] = __version__ + + +def replace_html_tag(app, exception): + """Replace HTML tags in the generated HTML files. + + Parameters + ---------- + app : ~sphinx.application.Sphinx + Application instance for rendering the documentation. + exception : Exception + Exception that occurred during the build process. + """ + if exception is not None: + return + + build_dir = pathlib.Path(app.builder.outdir).resolve() + defined_extensions = app.config["extensions"] + if not any( + extension in defined_extensions + for extension in ["autoapi.extension", "ansys_sphinx_theme.extension.autoapi"] + ): + return + api_dir = app.config["autoapi_root"] + api_path = build_dir / api_dir + if not api_path.exists(): + return + + file_names = list(api_path.rglob("*.html")) + for file_name in file_names: + with pathlib.Path.open(api_dir / file_name, "r", encoding="utf-8") as file: + content = file.read() + with pathlib.Path.open(api_dir / file_name, "w", encoding="utf-8") as file: + modified_content = content.replace("<", "<").replace(">", ">") + file.write(modified_content) + + +def configure_theme_logo(app: Sphinx): + """ + Configure the theme logo based on the theme options. + + Parameters + ---------- + app : sphinx.application.Sphinx + Application instance for rendering the documentation. + """ + # Define logo configurations + pyansys_logo = { + "image_dark": pyansys_logo_dark_mode, + "image_light": pyansys_logo_light_mode, + } + + ansys_logo = { + "image_dark": ansys_logo_dark_mode, + "image_light": ansys_logo_light_mode, + } + theme_options = app.config.html_theme_options + logo_option = theme_options.get("logo") + + if not logo_option: + theme_options["logo"] = pyansys_logo + + if isinstance(logo_option, str) and logo_option not in {"ansys", "pyansys", "no_logo"}: + raise ValueError( + f"Invalid logo option: '{logo_option}'. The logo option must be either 'ansys', 'pyansys', or 'no_logo'" # noqa: E501 + ) + + if logo_option == "ansys": + theme_options["logo"] = ansys_logo + theme_options["logo_link"] = theme_options.get("logo_link", ANSYS_LOGO_LINK) + elif logo_option == "pyansys": + theme_options["logo"] = pyansys_logo + theme_options["logo_link"] = theme_options.get("logo_link", PYANSYS_LOGO_LINK) + elif logo_option == "no_logo": + theme_options["logo"] = None + + elif isinstance(logo_option, dict): + theme_options["logo"] = logo_option + + +def convert_pdf_to_png(pdf_path: pathlib.Path, output_dir: pathlib.Path, output_png: str): + """ + Convert PDF to PNG images. + + Parameters + ---------- + pdf_path : pathlib.Path + Path to the PDF file. + output_dir : pathlib.Path + Path to the output directory. + output_png : str + Name of the output PNG file. + """ + try: + from pdf2image import convert_from_path + except ImportError as e: + raise ImportError( + f"Failed to import `pdf2image`: {e}. Install the package using `pip install pdf2image`" # noqa: E501 + ) + try: + images = convert_from_path(pdf_path, 500) + images[0].save(output_dir / output_png, "PNG") + except Exception as e: + raise RuntimeError( + f"Failed to convert PDF to PNG: {e}, ensure `poppler` is installed. See https://pypi.org/project/pdf2image/" # noqa: E501 + ) + + +def add_cheat_sheet( + app: Sphinx, pagename: str, templatename: str, context: Dict[str, Any], doctree: nodes.document +) -> None: + """Add a cheat sheet to the left navigation sidebar. + + Parameters + ---------- + app : ~sphinx.application.Sphinx + Application instance for rendering the documentation. + pagename : str + Name of the current page. + templatename : str + Name of the template being used. + context : dict + Context dictionary for the page. + doctree : ~docutils.nodes.document + The doctree. + """ + cheatsheet_options = app.config.html_theme_options.get("cheatsheet", {}) + pages = cheatsheet_options.get("pages", ["index"]) + pages = [pages] if isinstance(pages, str) else pages + if cheatsheet_options and any(pagename == page for page in pages): + sidebar = context.get("sidebars", []) + sidebar.append("cheatsheet_sidebar.html") + context["sidebars"] = sidebar + + +def build_quarto_cheatsheet(app: Sphinx): + """ + Build the Quarto cheatsheet. + + Parameters + ---------- + app : sphinx.application.Sphinx + Application instance for rendering the documentation. + """ + cheatsheet_options = app.config.html_theme_options.get("cheatsheet", {}) + + if not cheatsheet_options: + return + + cheatsheet_file = cheatsheet_options.get("file", "") + output_dir = "_static" + version = cheatsheet_options.get("version", "main") + + if not cheatsheet_file: + return + + cheatsheet_file = pathlib.Path(app.srcdir) / cheatsheet_file + file_name = str(cheatsheet_file.name) + file_path = cheatsheet_file.parent + output_dir_path = pathlib.Path(app.outdir) / output_dir + try: + # Add the cheatsheet to the Quarto project + subprocess.run( + [ + "quarto", + "add", + f"ansys/pyansys-quarto-cheatsheet@{CHEAT_SHEET_QUARTO_EXTENTION_VERSION}", + "--no-prompt", + ], + cwd=file_path, + capture_output=True, + text=True, + ) + + # Render the cheatsheet + subprocess.run( + [ + "quarto", + "render", + file_name, + "--to", + "cheat_sheet-pdf", + "--output-dir", + output_dir_path, + "-V", + f"version={version}", + ], + cwd=file_path, + capture_output=True, + text=True, + ) + + # Remove the cheatsheet from the Quarto project + subprocess.run( + ["quarto", "remove", "ansys/cheat_sheet", "--no-prompt"], + cwd=file_path, + capture_output=True, + text=True, + ) + + # Remove all supplementary files + supplementary_files = [ + "_static/slash.png", + "_static/bground.png", + "_static/ansys.png", + ] + for file in supplementary_files: + file_path = cheatsheet_file.parent / file + if file_path.exists(): + file_path.unlink() + + # If static folder is clean, delete it + if not list(cheatsheet_file.parent.glob("_static/*")): + cheatsheet_file.parent.joinpath("_static").rmdir() + + except subprocess.CalledProcessError as e: + raise RuntimeError(f"Failed to build Quarto cheatsheet: {e}. Ensure Quarto is installed.") + + output_file = output_dir_path / file_name.replace(".qmd", ".pdf") + app.config.html_theme_options["cheatsheet"]["output_dir"] = f"{output_dir}/{output_file.name}" + output_png = file_name.replace(".qmd", ".png") + convert_pdf_to_png(output_file, output_dir_path, output_png) + app.config.html_theme_options["cheatsheet"]["thumbnail"] = f"{output_dir}/{output_png}" + + +def check_for_depreciated_theme_options(app: Sphinx): + """Check for depreciated theme options. + + Parameters + ---------- + app : sphinx.application.Sphinx + Application instance for rendering the documentation. + """ + theme_options = app.config.html_theme_options + if "use_meilisearch" in theme_options: + warnings.warn( + "The 'use_meilisearch' option is deprecated. Remove the option " + "from your configuration file.", + DeprecationWarning, + ) + + +def retrieve_whatsnew_input(app: Sphinx) -> tuple: + # Get the html_theme_options from conf.py + config_options = app.config.html_theme_options + + # Get the whatsnew key from the html_theme_options + whatsnew_options = config_options.get("whatsnew") + if not whatsnew_options: + return + + # The source directory of the documentation: {repository_root}/doc/source + doc_src_dir = app.env.srcdir + + # Get the number of headers to display in the what's new section in the sidebar + # By default, it's 3 + no_of_headers = whatsnew_options.get("no_of_headers", 3) + # Get the number of what's new content to display under each minor version in the sidebar. + # By default, it's 3 + no_of_contents = whatsnew_options.get("no_of_contents", 3) + + # Get the name of the whatsnew.yml file in doc/source. By default, it's "whatsnew" + whatsnew_file = whatsnew_options.get("whatsnew_file", "whatsnew") + whatsnew_file = pathlib.Path(doc_src_dir) / f"{whatsnew_file}.yml" + + # Get the name of the changelog file in doc/source. By default, it's "changelog" + changelog_file = whatsnew_options.get("changelog_file", "changelog") + changelog_file = pathlib.Path(doc_src_dir) / f"{changelog_file}.rst" + + # Get the pages the whatsnew section should be displayed on. By default, it's changelog + pages = whatsnew_options.get("pages", ["changelog"]) + + whatsnew_config = { + "no_of_headers": no_of_headers, + "no_of_contents": no_of_contents, + "whatsnew_file": whatsnew_file, + "changelog_file": changelog_file, + "pages": pages, + } + + return whatsnew_config + + +def add_whatsnew_changelog(app, doctree): + """Create doctree with minor version and what's new content.""" + whatsnew_config = retrieve_whatsnew_input(app) + # Read the file and get the sections from the file as a list. For example, + # sections = [
      ] + sections = doctree.traverse(nodes.document) + if not sections: + return + + # The source directory of the documentation: {repository_root}/doc/source + # doc_src_dir = app.env.srcdir + # changelog_file = pathlib.Path(doc_src_dir) / f"{changelog_file}.rst" + # whatsnew_file = pathlib.Path(doc_src_dir) / f"{whatsnew_file}.yml" + + # Get the file name of the section using section.get("source") and return the section + # if section.get("source") is equal to the changelog_file + changelog_doctree_sections = [ + section + for section in sections + if section.get("source") == str(whatsnew_config["changelog_file"]) + ] + + # Return if the changelog file sections are not found + if not changelog_doctree_sections: + return + + whatsnew_file = whatsnew_config["whatsnew_file"] + whatsnew_data = get_whatsnew_data(whatsnew_file) + + # to do: get the version from the config, also get patch and minor version + minor_version = get_version_match(app.env.config.version) + patch_version = app.env.config.version.split(".")[2] + + existing_minor_versions = [] + docs_content = doctree.traverse(nodes.section) + for node in docs_content: + # Get the content of the next node + next_node = node.next_node(nodes.reference) + # Get the name of the next node + section_name = next_node.get("name") + if section_name: + # Get the patch version from the section name + patch_version = re.search(SEMVER_REGEX, section_name) + if patch_version: + # Create the minor version from the patch version + minor_version = ".".join(patch_version.groups()[:2]) + if minor_version not in existing_minor_versions: + # Add minor version to list of existing minor versions + existing_minor_versions.append(minor_version) + + # Create a section for the minor version + minor_version_section = nodes.section( + ids=[f"version-{minor_version}"], names=[f"Version {minor_version}"] + ) + # Add the title to the section for the minor version + minor_version_section += nodes.title("", f"Version {minor_version}") + + # Add "What's New" section under the minor version if the minor version is in + # the what's new data + if whatsnew_file.exists() and (minor_version in list(whatsnew_data.keys())): + minor_version_whatsnew = add_whatsnew_section(minor_version, whatsnew_data) + minor_version_section.append(minor_version_whatsnew) + + # Insert the minor_version_section into the node + if "release notes" in node[0].astext().lower(): + # Add the title with the minor version after "Release Notes" + node.insert(1, minor_version_section) + else: + # Add the title at the beginning of a section with a patch version + node.insert(0, minor_version_section) + + +def get_whatsnew_data(whatsnew_file): + if whatsnew_file.exists(): + with pathlib.Path.open(whatsnew_file, "r", encoding="utf-8") as file: + whatsnew_data = yaml.safe_load(file) + + minor_version_whatsnew_data = {} + for fragment in whatsnew_data["fragments"]: + # Get the minor version from the fragment version + whatsnew_minor_version = ".".join(fragment["version"].split(".")[:2]) + + # Create an empty list for the minor version if it does not exist + if whatsnew_minor_version not in minor_version_whatsnew_data: + minor_version_whatsnew_data[whatsnew_minor_version] = [] + # Append the fragment to the minor version in the whatsnew_data + minor_version_whatsnew_data[whatsnew_minor_version].append(fragment) + + return minor_version_whatsnew_data + + +def add_whatsnew_section(minor_version, whatsnew_data): + """Add the what's new title and content under the minor version.""" + # Add the what's new section and title + minor_version_whatsnew = nodes.section(ids=[f"version-{minor_version}-whatsnew"]) + minor_version_whatsnew += nodes.title("", "What's New") + + # Add a dropdown under the "What's New" section for each fragment in the whatsnew.yml file + for fragment in whatsnew_data[minor_version]: + # Create a dropdown for the fragment + whatsnew_dropdown = nodes.container( + body_classes=[""], + chevron=True, + container_classes=["sd-mb-3 sd-fade-in-slide-down"], + design_component="dropdown", + has_title=True, + icon="", + is_div=True, + opened=False, + title_classes=[""], + type="dropdown", + ) + + # Set the title_id for the dropdown + title_id = fragment["title"].replace(" ", "-").lower() + + # Add the title of the fragment to the dropdown + whatsnew_dropdown += nodes.rubric(ids=[title_id], text=fragment["title"]) + + # Add a line specifying which version the fragment is available in + version_paragraph = nodes.paragraph("sd-card-text") + version_paragraph.append( + nodes.emphasis("", f"Available in v{fragment['version']} and later") + ) + whatsnew_dropdown += version_paragraph + + # Split content from YAML file into list + content_lines = fragment["content"].split("\n") + + # Create iterator for the content_lines + content_iterator = iter(content_lines) + + # Navigate to first line in the iterator + line = next(content_iterator, None) + + while line is not None: + if ".. code" in line or ".. sourcecode" in line: + # Get language after "code::" + language = line.split("::")[1].strip() + # Create the code block container node with the language if it exists + code_block = ( + nodes.container(classes=[f"highlight-{language} notranslate"]) + if language + else nodes.container() + ) + + # Fill the code block with the following lines until it reaches the end or an + # unindented line + code_block, line = fill_code_block(content_iterator, code_block) + whatsnew_dropdown += code_block + else: + # Create the paragraph node + paragraph = nodes.paragraph("sd-card-text") + + # Fill the paragraph node with the following lines until it reaches + # the end or a code block + paragraph, line = fill_paragraph(content_iterator, paragraph, line) + whatsnew_dropdown += paragraph + + # Append the fragment dropdown to the minor_version_whatsnew section + minor_version_whatsnew.append(whatsnew_dropdown) + + return minor_version_whatsnew + + +def fill_code_block(content_iterator: Iterable, code_block: nodes.container) -> nodes.container: + """Fill the code block. + + Parameters + ---------- + content_iterator : Iterable + Iterator for the content lines from the fragments in the whatsnew.yml file. + code_block : nodes.container + Container node for the code block. + + Returns + ------- + nodes.container, str + Container node for the code block and the next line in the content iterator. + """ + # classes=["highlight"] is required for the copy button to show up in the literal_block + highlight_container = nodes.container(classes=["highlight"]) + + # Create literal block with copy button + literal_block = nodes.literal_block( + classes=["sd-button sd-button--icon sd-button--icon-only sd-button--icon-small"], + icon="copy", + label="Copy", + title="Copy", + ) + + # Move to the first line in the code block (the line after ".. code::") + next_line = next(content_iterator, None) + + # While the next_line is indented or blank, add it to the code block + while next_line is not None and (next_line.startswith(" ") or (next_line == "")): + formatted_line = next_line.lstrip() + "\n" + # Add the formatted line to the literal block + literal_block += nodes.inline(text=formatted_line) + + # Break the loop if the end of the content is reached + if next_line is not None: + # Move to the next line in the content + next_line = next(content_iterator, None) + else: + break + + # Add the literal block to the highlight container + highlight_container += literal_block + + # Add the highlight container to the code block + code_block += highlight_container + + return code_block, next_line + + +def fill_paragraph( + content_iterator: Iterable, paragraph: nodes.paragraph, next_line: str +) -> nodes.paragraph: + """Fill the paragraph node. + + Parameters + ---------- + content_iterator : Iterable + Iterator for the content lines from the fragments in the whatsnew.yml file. + paragraph : nodes.paragraph + Paragraph node. + next_line : str + Next line in the content iterator. + + Returns + ------- + nodes.paragraph, str + Paragraph node and the next line in the content iterator. + """ + # While the next_line is not None and is not a code block, add it to the paragraph + while next_line is not None and not next_line.startswith(".. "): + # Regular expressions to find rst links, and single & double backticks/asterisks + rst_link_regex = r"(`[^<`]+? <[^>`]+?>`_)" + single_backtick_regex = r"(`[^`]+?`)" + double_backtick_regex = r"(``.*?``)" + bold_text_regex = r"(\*\*.*?\*\*)" + italic_text_regex = r"(\*[^\*]+?\*)" + + # Check if there are rst links, single & double backticks/asterisks in the line + link_backtick_regex = ( + rf"{rst_link_regex}|" + rf"{single_backtick_regex}|{double_backtick_regex}|" + rf"{bold_text_regex}|{italic_text_regex}" + ) + + # Get all matches for rst links, single & double backticks/asterisks in the line + # Sample: next_line = "The files are **deleted** when the ``GUI`` is closed. For more info" + # For example, matches = [('', '', '', '**deleted**', ''), ('', '', '``GUI``', '', '')] + matches = re.findall(link_backtick_regex, next_line) + + if matches: + # Get all of the matches from the matches list + # For example, regex_matches = ['**deleted**', '``GUI``'] + regex_matches = [ + element for match in matches for i, element in enumerate(match) if element + ] + + # Create a regular expression pattern that matches any URL + # For example, pattern = r"\*\*deleted\*\*|``GUI``" + pattern = "|".join(map(re.escape, regex_matches)) + + # Split the line using the pattern + # For example, split_lines = ['The files are ', '**deleted**', ' when the ', '``GUI``', + # ' is closed. For more info'] + split_lines = re.split(f"({pattern})", next_line) + + for line in split_lines: + if line in regex_matches: + # If it matches RST link regex, append a reference node + if re.search(rst_link_regex, line): + text, url = re.findall(r"`([^<`]+?) <([^>`]+?)>`_", line)[0] + if url.startswith("http") or url.startswith("www"): + ref_type = "external" + else: + ref_type = "internal" + paragraph.append( + nodes.reference( + classes=[f"reference-{ref_type}"], + refuri=url, + href=url, + text=text, + ) + ) + # If it matches single or double backticks, append a literal node + elif re.search(single_backtick_regex, line): + text = re.findall(r"`([^`]+?)`", line)[0] + paragraph.append(nodes.literal(text=text)) + elif re.search(double_backtick_regex, line): + text = re.findall(r"``(.*?)``", line)[0] + paragraph.append(nodes.literal(text=text)) + # If it matches bold text, append a strong node + elif re.search(bold_text_regex, line): + text = re.findall(r"\*\*(.*?)\*\*", line)[0] + paragraph.append(nodes.strong(text=text)) + # If it matches italic text, append an emphasis node + elif re.search(italic_text_regex, line): + text = re.findall(r"\*([^\*]+?)\*", line)[0] + paragraph.append(nodes.emphasis(text=text)) + else: + paragraph.append(nodes.inline(text=line)) + else: + # Append the next_line as an inline element, unless it is an empty string. If it's an + # empty string, append a line break + paragraph.append(nodes.inline(text=next_line)) if next_line != "" else paragraph.append( + nodes.line(text="\n") + ) + + # Add a space at the end of each line + paragraph.append(nodes.inline(text=" ")) + + # Break the loop if the end of the content is reached + if next_line is not None: + # Move to the next line in the content + next_line = next(content_iterator, None) + else: + break + + return paragraph, next_line + + +def extract_whatsnew(app, doctree, docname): + """Extract the what's new content from the document.""" + whatsnew_config = retrieve_whatsnew_input(app) + + if docname not in whatsnew_config["pages"]: + return + + # Get the doctree for the file + changelog_file = whatsnew_config["changelog_file"].stem + doctree = app.env.get_doctree(changelog_file) + docs_content = doctree.traverse(nodes.section) + + if not docs_content: + return + + whatsnew = [] + app.env.whatsnew = [] + + # Get a list of nodes whose ids start with "version" that contain "What's new" sections + versions_nodes = [] + + # Find nodes that contain the minor versions and a "What's New" section + for node in docs_content: + node_id = node.get("ids")[0] + # Get the nodes that contain the minor versions: "Version x.y" + if node_id.startswith("version") and "whatsnew" not in node_id: + sections = list(node.traverse(nodes.section)) + # If the section contains a "What's New" section, add it to the list of versions + whatsnew_nodes = [ + section_node + for section_node in sections + if section_node.get("ids")[0] == f"{node_id}-whatsnew" + ] + if whatsnew_nodes: + versions_nodes.append(node) + + # Get the version nodes up to the specified number of headers + versions_nodes = versions_nodes[: whatsnew_config["no_of_headers"]] + + for version_node in versions_nodes: + # Get the version title (e.g., "Version 0.1") + version_title = version_node[0].astext() + # Get the sections under the version node + sections = list(version_node.traverse(nodes.section)) + + # Sections with text that contains "what's new" + whatsnew_nodes = [node for node in sections if node[0].astext().lower() == "what's new"] + + if not whatsnew_nodes: + continue + + # Get the children of the "What's New" section + children = [node for node in whatsnew_nodes[0].traverse(nodes.rubric)] + + # List of ids for each dropdown -> figure out how to match each child in children + # with its corresponding url + # ids = [child.get("ids")[0] for child in children] + # print("ids: ", ids) + + # Filter the displayed children based on the number of content specified in the config + if len(children) > whatsnew_config["no_of_contents"]: + children = children[: whatsnew_config["no_of_contents"]] + + contents = { + "title": version_title, + "title_url": f"{changelog_file}.html#{version_node.get('ids')[0]}", + "children": children, + "url": f"{changelog_file}.html#{whatsnew_nodes[0]['ids'][0]}", + } + + whatsnew.append(contents) + + app.env.whatsnew = whatsnew + + +def add_whatsnew_sidebar(app, pagename, templatename, context, doctree): + """Add what's new section to the context.""" + config_options = app.config.html_theme_options + whats_new_options = config_options.get("whatsnew") + if not whats_new_options: + return + + pages = whats_new_options.get("pages", ["index"]) + if pagename not in pages: + return + + whatsnew = context.get("whatsnew", []) + whatsnew.extend(app.env.whatsnew) + context["whatsnew"] = whatsnew + sidebar = context.get("sidebars", []) + sidebar.append("whatsnew_sidebar.html") + context["sidebars"] = sidebar + + +def setup(app: Sphinx) -> Dict: + """Connect to the Sphinx theme app. + + Parameters + ---------- + app : ~sphinx.application.Sphinx + Application instance for rendering the documentation. + + Returns + ------- + Dict + Dictionary containing application status. + + """ + # Add the theme configuration + theme_path = get_html_theme_path() + app.add_html_theme("ansys_sphinx_theme", theme_path) + app.config.templates_path.append(str(THEME_PATH / "components")) + + # Add default HTML configuration + setup_default_html_theme_options(app) + + use_ansys_search = app.config.html_theme_options.get("use_ansys_search", True) + if use_ansys_search: + update_search_config(app) + + # Verify that the main CSS file exists + if not CSS_PATH.exists(): + raise FileNotFoundError(f"Unable to locate ansys-sphinx theme at {CSS_PATH.absolute()}") + app.add_css_file(str(CSS_PATH.relative_to(STATIC_PATH))) + app.config.templates_path.append(str(TEMPLATES_PATH)) + app.add_js_file("https://cdn.datatables.net/1.10.23/js/jquery.dataTables.min.js") + app.add_css_file("https://cdn.datatables.net/1.10.23/css/jquery.dataTables.min.css") + app.add_css_file("https://www.nerdfonts.com/assets/css/webfont.css") + app.connect("builder-inited", configure_theme_logo) + app.connect("builder-inited", build_quarto_cheatsheet) + app.connect("builder-inited", check_for_depreciated_theme_options) + app.connect("doctree-read", add_whatsnew_changelog) + app.connect("doctree-resolved", extract_whatsnew) + app.connect("html-page-context", add_whatsnew_sidebar) + app.connect("html-page-context", update_footer_theme) + app.connect("html-page-context", fix_edit_html_page_context) + # app.connect("html-page-context", fix_toctree) + app.connect("html-page-context", add_cheat_sheet) + app.connect("build-finished", replace_html_tag) + if use_ansys_search: + app.connect("build-finished", create_search_index) + return { + "version": __version__, + "parallel_read_safe": True, + "parallel_write_safe": True, + } + + +__all__ = ["__version__", "generate_404", "get_version_match", "TITLES", "PARAGRAPHS", "ALL_NODES"] From 2ab588a91b0ec35d99024db9301228b87d20e03d Mon Sep 17 00:00:00 2001 From: Kerry McAdams Date: Thu, 16 Jan 2025 18:00:39 -0500 Subject: [PATCH 51/73] fix license file? --- LICENSE | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/LICENSE b/LICENSE index 3df6f8200..4a8652561 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2021 - 2025 ANSYS, Inc. and/or its affiliates. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2021 - 2025 ANSYS, Inc. and/or its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 01a24b51c98fff75f2f3989a48a2b0d2cc6dca70 Mon Sep 17 00:00:00 2001 From: Revathyvenugopal162 Date: Fri, 17 Jan 2025 10:13:50 +0100 Subject: [PATCH 52/73] fix: change the sidebar --- doc/source/conf.py | 2 +- src/ansys_sphinx_theme/__init__.py | 3 ++- .../theme/ansys_sphinx_theme/components/whatsnew_sidebar.html | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 0c46c4430..1e70a1bd7 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -73,7 +73,7 @@ }, "whatsnew": { "no_of_headers": 2, - "no_of_contents": 1, + "no_of_contents": 3, "whatsnew_file": "whatsnew", "changelog_file": "changelog", "pages": ["changelog"], # "index" diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index d1eeee2ca..5fa0e7074 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -930,6 +930,7 @@ def extract_whatsnew(app, doctree, docname): changelog_file = whatsnew_config["changelog_file"].stem doctree = app.env.get_doctree(changelog_file) docs_content = doctree.traverse(nodes.section) + html_title = app.config.html_title or app.config.html_short_title or app.config.project if not docs_content: return @@ -983,7 +984,7 @@ def extract_whatsnew(app, doctree, docname): children = children[: whatsnew_config["no_of_contents"]] contents = { - "title": version_title, + "title": f"{html_title} {version_title}", "title_url": f"{changelog_file}.html#{version_node.get('ids')[0]}", "children": children, "url": f"{changelog_file}.html#{whatsnew_nodes[0]['ids'][0]}", diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html index 2a2c050ba..5c0c7cce8 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/components/whatsnew_sidebar.html @@ -1,13 +1,12 @@ {% if whatsnew %}
      -

      What's New

        {% for whatsnew in whatsnew %} {% set title = whatsnew.get('title') %} {% set url = whatsnew.get('url') %} {% set title_url = whatsnew.get('title_url') %} {% set children = whatsnew.get('children') %} -

        {{ title }}

        +

        {{ title }}

        From 1a519e97acdcb5d7be1dc75643b8e0a00fb071f7 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:11:27 -0500 Subject: [PATCH 53/73] parse version sections more concisely --- src/ansys_sphinx_theme/__init__.py | 75 +++++++++++++----------------- 1 file changed, 32 insertions(+), 43 deletions(-) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 5fa0e7074..4a33e30cb 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -602,11 +602,6 @@ def add_whatsnew_changelog(app, doctree): if not sections: return - # The source directory of the documentation: {repository_root}/doc/source - # doc_src_dir = app.env.srcdir - # changelog_file = pathlib.Path(doc_src_dir) / f"{changelog_file}.rst" - # whatsnew_file = pathlib.Path(doc_src_dir) / f"{whatsnew_file}.yml" - # Get the file name of the section using section.get("source") and return the section # if section.get("source") is equal to the changelog_file changelog_doctree_sections = [ @@ -622,47 +617,41 @@ def add_whatsnew_changelog(app, doctree): whatsnew_file = whatsnew_config["whatsnew_file"] whatsnew_data = get_whatsnew_data(whatsnew_file) - # to do: get the version from the config, also get patch and minor version - minor_version = get_version_match(app.env.config.version) - patch_version = app.env.config.version.split(".")[2] - existing_minor_versions = [] docs_content = doctree.traverse(nodes.section) - for node in docs_content: - # Get the content of the next node + + # Get each section that contains a semantic version number + version_sections = [node for node in docs_content if re.search(SEMVER_REGEX, node[0].astext())] + + for node in version_sections: + # Get the semantic version number from the section title link next_node = node.next_node(nodes.reference) - # Get the name of the next node - section_name = next_node.get("name") - if section_name: - # Get the patch version from the section name - patch_version = re.search(SEMVER_REGEX, section_name) - if patch_version: - # Create the minor version from the patch version - minor_version = ".".join(patch_version.groups()[:2]) - if minor_version not in existing_minor_versions: - # Add minor version to list of existing minor versions - existing_minor_versions.append(minor_version) - - # Create a section for the minor version - minor_version_section = nodes.section( - ids=[f"version-{minor_version}"], names=[f"Version {minor_version}"] - ) - # Add the title to the section for the minor version - minor_version_section += nodes.title("", f"Version {minor_version}") - - # Add "What's New" section under the minor version if the minor version is in - # the what's new data - if whatsnew_file.exists() and (minor_version in list(whatsnew_data.keys())): - minor_version_whatsnew = add_whatsnew_section(minor_version, whatsnew_data) - minor_version_section.append(minor_version_whatsnew) - - # Insert the minor_version_section into the node - if "release notes" in node[0].astext().lower(): - # Add the title with the minor version after "Release Notes" - node.insert(1, minor_version_section) - else: - # Add the title at the beginning of a section with a patch version - node.insert(0, minor_version_section) + # Get the name of the section title link + version = next_node.get("name", None) + + if version: + # Create the minor version from the patch version + minor_version = ".".join(version.split(".")[:-1]) + + if minor_version not in existing_minor_versions: + # Add minor version to list of existing minor versions + existing_minor_versions.append(minor_version) + + # Create a section for the minor version + minor_version_section = nodes.section( + ids=[f"version-{minor_version}"], names=[f"Version {minor_version}"] + ) + # Add the title to the section for the minor version + minor_version_section += nodes.title("", f"Version {minor_version}") + + # Add "What's New" section under the minor version if the minor version is in + # the what's new data + if whatsnew_file.exists() and (minor_version in list(whatsnew_data.keys())): + minor_version_whatsnew = add_whatsnew_section(minor_version, whatsnew_data) + minor_version_section.append(minor_version_whatsnew) + + # Add the title at the beginning of a section with a patch version + node.insert(0, minor_version_section) def get_whatsnew_data(whatsnew_file): From b24c78490e7125dc13e23177846e267dcd90ba64 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Mon, 20 Jan 2025 13:14:29 -0500 Subject: [PATCH 54/73] Add documentation for the what's new option --- .../examples/images/whatsnew_section.PNG | Bin 0 -> 13611 bytes .../examples/images/whatsnew_sidebar.PNG | Bin 0 -> 9011 bytes doc/source/user-guide/options.rst | 87 ++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 doc/source/examples/images/whatsnew_section.PNG create mode 100644 doc/source/examples/images/whatsnew_sidebar.PNG diff --git a/doc/source/examples/images/whatsnew_section.PNG b/doc/source/examples/images/whatsnew_section.PNG new file mode 100644 index 0000000000000000000000000000000000000000..13d9269e878d4c8381200186694881dd73094421 GIT binary patch literal 13611 zcmd^mcT|(zw`Q6^Lb-ETS0+LEqVhF(q7JAWyN#t>TylQ+^dSIHlSFrFcbRfc^GeIy z7XY~7_vb^kP1fggX}(V5m+K<0-&@=X zdPOh(tqeyi(lTIW&$Mxs=aoS}KPb>m%x%H=MoxZF`mb+PP#zq-PUgM5f8JBA85wJN z+l|ztyN9*dam#B~F*de&+M2X2>L3uxb9Z^YKS5jDW=ID!{PE!3nzWSvL$qNKdP*tq zZgfS{d(n1j(cGGh?^dY9A^}@^TUP71%Y*A{4&tUCU-FT~uQSQN#a)N6v4xi2_`8Pt zP&Y``K_%}|rmjF?(QVC&iSWDJwM$O5ccdl!OcEzmX0Rc%t(Mw`PtkhAzY9!=%^)rE zs&N==z`Dc9X+A&1V<)f5%xWI8m4ca~XXT7-F0qdBLcRF5`LSDMSO#Xh=D1;ARU_AU zI5<`NwryvuV@{}Ibva)9^o2pKWeu(|BR$hJ#<4meslHdF-_XY&V?Lrk_~OZ{?CD0X z+o_pK7}NvJ1s9~_NZs~U^=2)5pEcBJBVciDa)QiP#-k!7;A>fM6@B7!fbMbWXU-mYm$5KsQgGw{H+U`zMp3BCJgE1vqKD-(&Ig zbJKk(JyM3$=7@&v!~FVGjvp-Ag==zW;PueetVrkQQtQF|UY=!pnmSU)Lzf@#MAXx( zxQ3fRwET=kuccW~0x&jXq*{wVw1cs60Q#%C?~z*68f5A!@J zKc#Zh=7Wm8xp>a?*OM)(7+2AD6$j&#dss!=ug^st9A-;Zf5jL~TQ?TJM%b{YYHG3O z%Wb{)ot$RY9|Ca{EmlQd)e+53SIuiNy zQtqzx%wKk+(dbQGL0SG_7y<1x*Qhz&ID8`bBDF7RukJ23ytEZ1&ElT&Jwsv47!=A< zNk5dhD`%=;rxjr?;p2uk44X$fqCqcPYv$%+V{yM*qo8shB9ctlALZ&X%O#rUaHgtk zDJqg`*VXU5*%}+1qG|iU5P;mN4=26djt}q~gv@LZ8&s7X;l+Q?nVzMD!#z{ZjU37B zw1{6hg&ect_{yz&-KMv0znvTQT(pM8CA*C(Y?%4snM1p9?WIR(xuGIAozce{6KwEg z>Cy#^`LH;%%w^_xDyR#?jSbrChHVZp-iNMG`c6Z(6iYefQPq+7&6*_wTYBS@2vSv6 zeh}ZYw^zK+cIJ3JIonD#$UnM`7p3YdF`3!Ps<0=rU2{9i4b%h-RUEnPKO` za<&mO>G@CC?D%&4FvM10dq!zS-6XjK^q2gr;AfmjY322$YLRm}wpww03Y5g**dgc< zXc0NarpIhi0NNzQU;g?5y7?Q;Od)4Esb7Fuu0<$4S+m7w&e%1i2fkPHP}|hF^DW7M z8%r1dO{2z4wg&12HVF-jQ5hx9hJG;Hn~eGH{m}O$dB%J!B#@wnmWg~P$9*X z2_r{+ZRy#m39-%3E4{&Cnd$q_%Xr=P0)*B=8QEr+vp-p$-f{FV+AwoTppj*-z1ne5 zKK_li%Am<>n$&qOb+zo=Qg|N1nVwntv7*rnyn$CdyaY`w$YP`#w|`o1G;{DYOA4dl z5#_ARBvqi(R6u%Z+){=;w@TlZK_`*z*w;ujAag!muNz2t<%IJ$^hVK#8NY!~LQ@^j z4LT2CELg>R8>&RPpR?8b<~+t>cQhoGxv}Yf39lbiydkM?`7WgXmAta5H~OT1nhxjF+@BPi0jT340pckL6+1-;5(u*p;Ez;4f} zi>aBN2DFJ9a$AYZlSP#nY7BOvc=zzze&k4>e@H#B@4zIPda*Hz<1L95=l}JJ1V1eA z)Kh0-Cb4W01KnHU!5!X&A~Du|icGKfTF)^hDer#4*WxbG&iyGdXOc6?3frQxzH1lyr&c zZwXv|$V9XRXDzd-xuCz!3y0d-cgMzN4;(N8ISus$gzZ0!;r|XCoW+=hJ$rk=g}(2Q z>t&gzow>_JXneOVTBcS8s#IGkxFVKZy`@os@>EjVAhp!C+JEF>?2`amwC2GLoiB6m zpua3zeJp>a#>9jiW}pT#^TP(!1m6fwz&7|cyLZml7yATu+`bR;m(c(bUuce}^8GBR zToKe2tdMTWGPWSMf)n#Di`?|IMIlTHW7~bFQ0~68?<{Ax*fm3bE_~dkUjp3-FQ26C zlVb}~a%dOX))navevmHv63jxF$+EWmJfcvh)7WZ+i-tQbC z(x?$%Zm#VWAZS1`>%2#wi;gBwFR}4@amouS`_u2eBZEHHp2*~kKb8TDXjrw5O@qD4 zKy@%hj(8C*DB1e-#ihfC;e-it zopoCX@ZS7BCNuBTb3$M@8u$4j=`OI;B&Yvkl2C|`*2G?exCv#G=5gGFOg~&UC$c0S z*AtGL-EiGJ+SZV}XBP$%*tGMwKZ^^=TtM`C$|$cx&(vlXW(3Zh`*ic{8r4*O5IT$0 z!?))ds!lMjGTrj6Xvl4Q4_TC2dh$LcY(caK#L>*LFKd@wem3bL6_rO1Q~GaA_*O$b zOk>EHBQZ|v)YX_9Qv1;XIdAFcreW!(O`+ej9&K)*Y{oTICY;5SP1sLkW8E>)QS0&n zby6@iI@Zltx>+y%1*Wfgf9gawIX}sqAs_-%0$eL0=li4N(C6YDkk&++bxhus3-!@T zK`G}O=GM6Fc4>Sttr1_EklJNLjm6fCTq-e&i(GrfQ{f9Ej&W0n_t%xy*O(IPCi}O+ z^5L_y{9O3?+w+9HBJ&DR+n7VUNef z;znK~+SX%oODa%CmvCpD$3T7u#Me}>-lG&6wpK~8xzg8$)@lOUM7cDF(%lD#uMT1w zp#uJ1&u)+cw97!y#;xSarH5>)dCA!9XDXIHW4y$sRb3yVa*?6>`?ygaupF$@! zb2=yRVBlxV=aH3-_9_agk{8K)zL%r044Z+qbJTX)v8+2Nu69&0T|~)|y}8@N$Kv_tl~n{~TZaFB9DV9}Nf*+oD4YD9V=M zPT$$n&J2>5=p8?}&cu|xJi~~P*h^Mz)OcBwVZTntb~m!3iHb!nBe{Et3#;IuEX9wt zy62~&skvZLsS9RV;!Hn}r1==3l6+rIJX3ujC@P*mNk|8Gn=>^tWI(Z3AyaXBy?ip| zclt^KeC--y?m5eetL z$?-)0KoPdQG{aZIm~|Thy3c`1%zkz%6|#7`8a9WiK;?cGr7WoCmq;k;aIBtQbwhTy zVuI+TTCM+lO?+Q#!F?gYj>oL|o)t}8f3(Bni|$|HhDjx(i|O19(J{^xn)x~)H!ZR- zYr&I)9${8)7>#CV`7QY;ryBJQrSKS`lBF~sKJ+m>UhStIKwkxAVYAg7ZdDsl;V<*T z@V!r0>lOSICufzBuJC6R z%719Yex#|hw%La=&1}6Q(jY-6bvE3%yQ{J;Rb<}Ky?y&NIZR$+E?`0`H7gm*;cMW+ zFA5XYIbVy{>^%AS-;8PzR#Ebp=t@p<3Fm)KweW^r=()?>Y1@?*QkW)Tsvcorfr za;&~Q?P>;AOg-c9HI`1~xCZpSM%z+8Vg->}zau6s&!HR;8_W0+cN2ov!VJAA+PP+A z7sX-6Q>}3#VY%4WTh8AmGJK_~dH5YB&`GCwOrWr$ofBb#4YE`8)2q(N{xp@TiuIs@ z^&g#yv$Y!0e1)SlcuV&QL)ptt~Nr$nT#L#!{j4alSevzC-ZON8A!Bd5wu`kUGDnY zqd^EkSVAIC0!>L#Mr5{e6#GVR>aR5HRkg`lNN|i1hth}CRwBeZjB6Vr(g(Ts2K@t zV89vs34HHIBtNA55}M2KEou=t9Oe8caDW%b3;K%I+vke8BBGahaCLnPZs^JL%6PFS z#iuF^Ft1YY!`%|S5{@y&xTm!npapjr%6`_TXKk!P7ue5YFI3?=wahI1H^|9RA+9!Bd z?M_AUh{Ym%tkm0jD_It0A*_6iFzbaN@d``(jVP!|^4Zdg&~jpgM)H&wPQ*|uECjfE zni-c?==;My(XJdMAA-s4y4;sE67|NKW}U*ypKM7jI;A-C@bOkQP?DR5K0$o+KKA+G zh$WA^afYuq|In?HstmriM`EsLeqw)04&<7hoqTDU!-SdPL;n_MQ@^hNAe1e zF4n>xV&^6sRCuFZh54=cXq&IpSzrA~l->!=1|2XrG)KPQr`|^#blYFZIMd&qLXFbe z%T6IPe1glLQPVwK96WQo+Y!_%gf{b|PtugpP04mLE@dwIYcyU>@7B<#6l%Q}8*BO9pC0j`7qb90mt-h0y_J>k*XFb5eW+d5 zW`mM|7QHB~S$XIkKg#`5R>VRVJu*v}4xRu$r=4TV%=#-WEVSGvz&TJYB;|9w$TeU` zEV#jEIKf^Qx}Q`ekm4;lW!(cel#mHYZKP?_EBI~n!wyr@{~Wuq$QQA`&(=+4TiqAc zF=+F4Z)-G6e9a*FRZnn#K^S(&YZ?pEK*}#+)u0p?d;J-J=+LCGBlE_ID7LEj9}3ec zrdVZ9b~0o6)f*vdJcck!vkMqDpFF5H=o`_2H<%MI+#$)Y(v5NqIdLXeDk~=xE9&M} z_uUXf-RMd7s+PLO0JKiaYb=GcXt!sjDzwqf(*jBAMLZSa^DXixL)O@uh$2t7D9d?> z{#e#0qd;X8{;*MGaYi-M!pYz!?=L66(4NVFHtlSB*ga#{6+Gzn?US~n&(>-cTIDpJg(*Qb zYSdKN8kB5r*Y_uL7$i+|N{ffR5cg@{`}#0r*t8Fri@ZE&^ZPa0GK)Vg96CX|u6DB- z&C2vTt{H}5`>SnJdBW67%fGx<`LHO(Oy8(aB^ZJizS^DmQ{^osHNdOaZ#{``I2b%C ziXTbU2zeac5p!EcMOo#bo8Fa8&7|c~f6cU!+ptl7L(im3DXP$4NgH*pk}BCC0t^;4 z(m2ee$T05NqiaRKbHh2&A@iYCzV|+hs}YcGRntrTjm)l@s-|p&1!bkyV5;z71j&4=7iys@+|Wcd?haeyuM=0m%F#0i;WZ)BC-QL$`xnc`1eej zfsqzo?om+HcGxf}cmYOkWE$-qr%TOj@Vv^r8dtE(oWJ@0k*CT8(NJPMU^?WQ1m&j) zSnQc3(}`5_s3BK5h@u=5KPv^5z0H_2xH!wN<;@lH4>4Y&j)bZl4`RRUcQ!$K7wQWQ zq^H&B*2id zHrr6L(+yvbn0L&+n=xGA6Ry&q8*O>x{<4@%Sz{z|q0^nXtz}WWcX<#OkNTvO?xP(J zJ}EV+h()AsjfyU1rfgpI7Z&!lT3#&L5P^l8P0YPx{@4r8aS%_?`C=7l!I=CFQ;R9V zWt@qsbuCR^13HIHWv>|eAnTTsA^v%;We8Hor?j1~xf7s)b_p=h>8GoD;@e=?o<3vC zyxh{`Jy%K~TBKy4=n7ha0G9@453P&F8D9h1BD_0{;{!LEUmUY!tnSA^rI*%Ko8(+N zUJTf7FqTZIPhEW+siL)1`)PaX)d+-0UdUEcPOvC|)OdN9lq>~s{MG?MuCJ0G<@{uh z2_e2$q$HgiyUbrGDOVYe8&Z6axES-T$)FIP=gEGX=*RWt*{#|#YM?#F$>7EkUYg3X z?W*J77*D0^kk&=UVh71hwuWIp?KSjMo$wB46o`K4b3;;thp2MGiKunk2gYcqo484> zH@$gXTtwplWLZ12BT*EG`@%x+X#be3K2%^>d1dTNDedQqI-Pqku291BQ19ZkX1lqUHnr&~QXw*! zc0^#+@xl*z4saFJKP=hK{#)AWvgA4?-?w@(^({UwV5CJ+jX#v84)|V`O<7vJL{~bw zVh<4WMd4~H;qEQ2>Q#cvap)t>g-tK5KO(u8<9}T}|Ia5E94rvq@H1J8NS|t#SuAC?x>KH{FNm zvFK5*FYY%WhYzEpidmD%NBwFmaT2gsrzA8vkW6#yDAZW9Jc@qU@5Vz>~FrGpM0E|;-v1M_BOt+k9 z#*3q%oH-!y#=~IK>qa@0XMbn0*(4P?z2}5*aOP872ff+=R3BQptH}WX4{pjR$!N3> zYGxOmc<6xVyGu5@UEfz+Et4)$C7=4jnE?RauX6=#U(CN`{_;l$1=c;MqD+Y%gxq*R zfaZnifG+?ZIQ;2DMi<`dO~~G+FH_t*R>sf(0H1zrj?#H~39suti~#$_KO$hc}f1w(c7y&;S8|*bh!IPO(n!ojy1XJN<6;32y0D$tFO3Jc^?I@G2vh67; z3&sHs!qmlSbAuME#D8Z7#+0yqHUFBaL74{N68HstGTXK6VwAjy5N`bD|DDxuUd}JyR|9q4`X5B`1YzF+sb!h7zyb; zWMcX0Mv-==SXO8Dnaat&4K@^;HIj`VCGVI{xZA{Rk)`qop)*b75uIJuwF8OdWLezJ zINNN#s%r>uG&%LQBx(QD-TdxNy5vxN;QGNFG0UjvBH*umA^2FH8lj$G=kjX9$GVE` zI)oAp!kh5rA*DQqrycYz105%y_A(Qj#&oNWEi1gnf#FE^3s9pLh5I~zS#|!{UJ$w3 zS6hS>pS#DrM0$GA_H!$VrUp%h-kN>55fXM>H=<-qC|inFQ;ypuJ**q6OWFMtApXHz zf!vA5Q|hHL9y9e4JXEFK$2eQ^y!nzSHNrR&dPVP%yrf>yDmnO(L_F;Lr(T;j}2AnMOhxS!2WcV^x{qBqgTR_>%ws9dekHXq7J!$e7Hd5 z`YY%2rg{mk_U3&NY6PKDmJ8CELC-iOnZ*flcFUy)yjk>>*AA=hQrCk z@HXA7tC+dXZND~8#++<_^7T9X8I`&Bs3u>4Pg)(;lYM4SE5g97i;claLzdwI3~hB!!8jiQf}Q}fEU)|I=&tr<=9)$fBM-Mq{s4S(jiyABItI1kW5z(FxrMOY+fC_ zS4V;wb6~=Iy@AJ*QR}PKlMSv>P>v5*^*aUTEbF$!B=?f1YT(eMp<}h*f8i{5%WOC0 zt12FpF+o~8742LI5@7<~i&^Qv(6v7JiNL^BM%iLeOc(`pI#bIOy-G=YHYT-5RjKD} z^gwU;$GMsJg;v=jT6SJ0l`xQrAlb^|8lc)lW;yM%#dXM2Mqp3Cqs$J;I~|COS3kPu z!XKPmK}+pGL&WMjw^GjZUu;np<8kou{zV265oNqTWJ%(ptNhAtXS(70Au;Z%jIJPE zk+xO%)=jcmQ22k=s_<6x8av$bk9t{Xml%_z$qEgKt0pfa^@~ls`BZdmZuz4K*XT`IV^v zcX%U({vb0GkMck0O8q}gxsJA{xF4TwDM2W61SAw>7R>EDh;dfU3pl4-|0}pK`hhoE zgDw{ge|ta$$Y;r7%DVL@=1^`6x58{5{igX5=0T~J=l|=$&_!;F7l7wH%AV)=bIK8c z2b|OtJpbbl5QfBtQSpL5l zc)d)c6hEwA*@_ky$%70k(Z0448iz%>wS=ZXqOt6-Sk<7qiPWC%7M)pQ5tiybXPdB{ zv&W7>)ptne7VN^Cic6R|QJ5sAQA}{Lb8o_{L3E%u;&tHG?n~_Irt5p|c9-*c>LMZp z;%{qGv#>kwF!sIZY&C~e+9J9H`Ml1Rq}%Vk;T?`i;`3<^ZTtT6-g|Pswf{A(q^ErWlSX#^+f2~A=E>U{1 zcCV4uWLJ6%o@eBjg7I!hCgw*=%VU9%RSELn8Kcg;@`L)6^ghZ6wa&&y@ zVo+=Q*+zUU=kuW_V)}lXKugd_CNFJrdZMoYmpU0oz3i1lt@=0cm{W3M)e zbUSR)#T!ta%d;}qA)`O*w6ROC4WuT8D!iJ@<2Qe&4I&oOhYTL;Z+(+lqLb#EIEw(6 z@CJ!Vw4nV41~Vt5T2y$Ii27NACO@vn4tDtoFyLVF@;scuLi|cfYnIS>@o;$QOW4rh zO3h;JqLEKc3~0D(m3{hIKF&-8`c{N4IdHCGlWShczNzO%aHj9h+#`kKU;fOm*1S<) zqFV!jqSc;BmTR{gle8KarmYo|WXn{_bP~wddSt>MMKtS%?;fEYck#yF9K zxzoTNd3s^L#4o%legLk_GVovaL%RJ`k;Z~5#0OTS@7dl;1#YDs?cnsAFcZPWFWux5 zpp!@9+DwXz3VvOlYJa4N0yn>9mq|mjFKy#_Q6b`gl%~HKAUBx9(qk5Fjj6mox*0Fb~Q0IlAY?(S8yd&lqxtUy3DI zeZG5nAX1`5CQ>gp_*Uy^jD0HM$D@eGkaqS>L1o~Wk;(YZ$gWR?&qba}LY2SrdE8e= z*yKmA!&Y>5i`hJ@yLYqhUw|(f;K~mMkNl6mAWL1fjM)`DtvZCCh*aciWEvC|8OO-g zkKIUTn>0(i2yCOP*pUpLt0hc-ki75Z5(8D4DP9aNev9<#oCUd(lWY`1e^i*1{p}xk zXye1EPvjfNe=D$Zw`yE#sUDzzl<{CMwWKfnWhqYAB%nUQ=9ST?{tT_^U*81$$nQv% zZwZ`L%$qRb+MC~(cB_fVN}n^7&7o37=>RU=dyF1!(Qy?pev=Z>^An5~T)R9(687MP z1sct_I=W?vKk;;PtN|uYnOFLH{5FRzSq?g`S-kgNd3}u?esnubzIjh#DuXJPHSSp&VNFbvdxs7b&`cy zy#L(aqhlQ1R9-;5qRvO;a1VJ-*;Ey6LU9O4$)f%gkX`g zU>bbZl{du?!Ijr5uKeP$wuePv#Ooch`P7 zL32*+u`ZNTF*Y3b45e%^K=B^o*Y}X z(7}&H@yhuRy_vByD5oVQF%*7K{ViQYsn-JV0s*PhMsWe%;`fc5E8gKO&dw#(-#Tgq z2KPV11(%%=F96)B{+mMge?K|+4218qTvuY?(&H_xl zMPh-~@=eh~;r{s@@ftI|M(#G@xGgkQ{yhp(ZqF6^W%oVdxP#h4i#3aszbh(}+8!yC zvD1BOw+xr2fNR6>Y|Pg1m4UNj4Sm=;>{To*!R6nWgbts}L&3ZnGDGhwCU1XeHvRyQ zw)}{b;7U7;S@7p_OAmb_t^?cX2Z3O?4lEm9QT@X1#IN7-dg?D$PxB^u!DJ|)$$YuP>(7E0*{4TCB!G^&U$O4y`F?HZrI zv*J_~<@7?DpI%**0+kujh>pc;5tmW9L_g&pcDH?1`9!-;!zUll%6!-hYysD6{IUpa zUz1b!Cl+O$_EOE^jTBHtXX6=G@>QXE*51K!Y-~zXHWq6}&k@=|OV&M ztHtjW6)KpXxuee*I=H-v1fS&47E7)rlatNG{)yxORV5+T-~gp?^it(|g$AU}sDr_= zJ7>8EUlcm-tM<|~aO^~A_2l#s+tFap7|f{3o|(FnLP~u7JN&NY5|B9&5qv%!GpGnc zK+AbMYb0j4$4pMymvyxzf^)6y9%&!EicagSWtg)iX0SN-JLFZ?;r))$4n%M1wT@K6 zSJG;^sJK=7r-)SF^)nR6Y-s5Fr_fd5AX3s*{K$*pnFWc7-!1R*mTbDUeNgoVw#Znm;XYwtRKr3dnsM(x_T+u!=8%s~g-V^dQQ zR?gPuCYVmS>5Y^?p5zyq>cKh73^7L%2FF^P7$ln(Pr$(()m}I%n zPDeKO5pQV~!}N}GDM7GIXi)tZSVaQhn==vZ+SLmDgckcJ4_z-V^HpMa;YaZ+Nn$c22we#BJ$*G-yI$ z;!^M3?IkLFYBXi95|ND_4nUdUgYydl#=32Me>@K|S8t0Sw*F#=+VSR-zF9RNv*Bfl zYkT#rAzbIhoLkRi4s;|FK63l2hB+(oG%;L&?1aq_-ceXe0R7bm>vSG_rAJ@bBlG32nFS2%jcjl8jXJ8}_ zOK8mujqqCFgZ01Myu6=F zNgR8xsh#@tu@hy2T^9wv4C^wuMsA0ke<9Drc6rLDLf5}PyfBrvKSHou<>c zw=-HnQZ@&BSU{0B1e-=bywZ$=>cgG>J?CNkMU80;z{jUFiR;E&GZ zB1k?bcBV4`C1T)GZWSIuU~zGA#j7CVmi6)J9%6M8sFq66(`Qu}DB4UyU48wE!@o55 zIH!20(NJ#4pR&c`B<11w{VcvL9?CcyT@_s8YUeviKH#Mm-zVqm;phGTGT*5RKO4r@ zPSgJo-GLiQKd$S8i29);*U{wjfV($o$EemROdx;&309=^x3PzBLJvLR4qfq^bNffe zcWGQm$CNnMUt8Ir3QCEtUzq8<2mnm2qKiHlMi`!<(C2FovGV3xb-mf5^+i2~40OQY zg-Ma71D&_DHvxcmzsoH~nRAVUDMID(b`N82jee+Sz?@rSWR$aH`pi6~IKrAA^q{-a zvg%}N!V(xwVNkG8ORuH&yP0~Am%_=REw7ia@bap@al7Ke;v(oG=knOa#Kj40>|8x; zQs?xwRKEd>F|Rt=zu*@ZX5-V6_Pe@I zrF$@HMD>OtsU(7`^lUcBu^^&5sMaXgIEqp%O0*$WndfKb&t0e2_b!(<^QV+bjPQVl zGK9rHjo8dqHU5m=h9~ZJU3=O#Pk#maPqk{Y$FPA>pHa>%Du`#} zatUj3Z0ylb?CP6zIvbauZtQAou9)3i9fUHQ(!+;ASGnjZGx6+5iJ{E7=}*n=ijs`6 zk|A8mxx>0{d%vD>R+TB}r3XGG`p-M;R<5ptkA19;pZgoBtZYpBsX{60$$)t&6}@w* zay*fKIKJ9rPK$CrPNhd*E5lBR@((@)?wE=p|D+efwMP@F=6;0}S{4lP!pMZynHpg{sHE$;3F4_>@bq_~vg(xPqA z;F3V`Fa6#*|D2gK=X^(I-kI~q?lZeH&+NT&-+Nuxy%9zRT9jl=WO#UZl-gho6FfY8 z4qPE7A;$Ie`G6~MAAD~UEj7IAQ5H0=LFlNeuZo9P8%KWif(X|p^#DKh#>1n5{w?^+ z4(xC6@VExGHB`;s*zIMHxhxD{HmwBd2#G{B&Nax74U*zFuCAIKBE>cg5{Iuf4Jy71f_P z;Z&5-f*Fb4y1hK;yj3CLltKoRaL)eMt4|rh9oX>zi(bFcx2rN92M>&Y>^%3#NI08i zEI3IcFCAA=9?`ia4cI{npP^+QmAi-hz{J6>S+?0t2Z9*L&milWYliC=fQya%%HAYv zEqLkM{tCJBIPyXH2XC5%kzXplz$d$$w*QbUn_2^C_U9aHE~f}F-UqOco%oJ5d2(*Q z&J&eWUC5oFHnSnFmw_@lJ}G}LEl4~}Qt*|zImj9CT@?j-Qi90ugrG5byvV#EylnH|m7Y?>Q#a;-_L4@7~*Cky<;o@cM`zSw9F zJ&beVUrOTdOSTSpBH2(7kajG5D#+gtUt`miXZ^FH&$wb>v@oLOZ2#MT7}3!MztgBy zqHhKlwc3i|MX#Rt_>*+-99O3pDKZVV^PJGocwP&9-{h4t8xZ`b&^x!5t>DkHRy$H| zg)Ya8=OqCPgo23*loO(?tM7gV2oq&m^inyV!B@tU8hNWxe@@rlX+_xn61 z{=pSDETL+4?gRV?aFbMp6N_*0KARPnLP{xAGI~<9ed{LIKgo;m7G^x>pZiZCeemMk z4!&j@H^s6U%)j!sCZ_8{gifcgu~4$H{PEhnE!0QXia24K=Xz3WtiokNb_~RGaen%E z+O+zIOQ=`SMJ~IUahl`o_o@O^>92^>=&{eDW4^AFR1anznXHU7N*oV(hk&-ILqbsM z75FJZHd>pj(4xl*f@lLvd0oA!js|GhiWq^SLIqk}>U5JbAR)3A zyQYNUEQ=u>#Z40r{@DnAG|CqOlRuFor2&|ntt=T&&d2kQFRlohel#i)gRx5VWn0Og zOd!%Ly)W!$F7z;;rDMO3$lhHz#2yIi<@QQ2*SNf{#Mgi3?Nrc#1}Z&#_^?C!vTsxS zbKYo^e5oH#6f+4w*VTNIfTloZKgowq!x2edwkM!zbBujKnjOo80v3a}+ZoA~++X^m zj@#makph2(3~A!|%U`q;r}aTv={r1k95V&*%T^pXJDzLQMh1)T^Q9g>$#%E^%A33>k16rw7wG)v4F0c4^DKxBd5S^rrzc-io~x_-on zUQYqq(j>nAOzOf?QQl5Q2mBnsAl zj5*B^Eg+$`DJgw^&rit4&|QzG{ztz@b}kS_fH^I|@_g_&6gfV<*L%-cxY34`(mgo8 z;}mbN(`3C;5c!kPJY`IydNshZeXHf0hDzBc7(ao?##$vGx|Lyn(2RW^P9HGfqB7JN zOxv|kuHt@nrgqx(3(N0=)H%VZUb85zwpMG3DE=_+ge-N<I{z}vXEu0Hlrt0IiaeLiahQ#h860vaCc-e^s}ga| zKLMtcC@GjFtQe#{V@X;eBir)r-mPwlV>%oqW(bhl(Y+8l;j;4fr6q02GE(Ve^b_H& zB`&=YN)~BklW4344IbbVX^_+s|NmJ*>HjHbS&5s5kv51yys{sTK^nd^YaCqPhwqU2qTCy?VOUbx?35z`bYbi7xcz#adpOPOvr{ z$DIex4j6TQn}^RNG*^WhEV5K!xiqHeQhdn7aJ;y913tUrk-N z^N$8o9F6;iUR&He>tTIh6uztrmzlYbiPQ1emwx<7rv!&Fej~3Of^S~@gHh1=d+GC? zmvAR3ki}IT@??@J0KZ6$D;Op-`WPn#FkkBUa9*u4>6{f&Z7((gn(W>%^uv>cqwJu5 zluM#~DAx^`9d^SQn?A~I+<#}tetTzGsPLSV5ma0lx8-~N4~cu}dsqVUFZSvTOMqMS zNWT_n7HcsC#w;WUe88OO;XJRvC3OYkA-H|9L8izh@PK*#&8UhB_qy7i=8hrl}S`O`+_w z`z=`jadFfe8qi-z$?AN;31aOTYT>_G(zINjT$(e#7UMIeWfzIa&F0g`hytRol-hcv zF1Ek%O=V<4KY^u;GjL&BvK5T3zq*-JQymsO_?mT#gCB)qv&KPE*_Jj9#wK%tKXTaK zKjv-qWdEnIin~av$-I4kuCSHoq%s1!d{^ubOJ`2vi-4x!#cYa9%iLJAHpPU-H(#sH$#+`xo*G+r=IoR&$F}7RoOM<%N;1|xHpyI^gTP?ywCfL>Kg?GU zGaV$;(qlwqMMaQ@rs@|-n3<*6j+On1rkko>x*2XI$JRWv85)gzqLsCbuZyQv-FIMi z+n}qcmLxzV7i|O+G=!K&u0+mcG2(!4WlbG=lW1?KI0e6OLN(7PNrf`L+&a+KV$Ng# zStJO5jojwfl8g4MPl+>e|EZ@&LDd|ecC}q)tGJtij_iU`iI{o|fE%YW7vt@~}AnD?zifSAOvm6D5CU zwH(L7`7PCU7T=FP%~98a2{uTZR#qxV3~Z3_KX$5*D|^eZ6lEGum6yD#kV@**1=PAN zf6LS92&UYAwNRWF#$_J1zV5(rETY4_)Y^~2l z6JzP*yyZ{hNSusYo(|GtUQGArCvTQ;MKjL;hq60hr9{xMwZc!{fa7Pn4HEUb_w;*s z^KXHKwA{v{KIKU}Wp-}N3xXO320|u;2ThhcBuv1c_pxF*_C92(Pof65RU`)7c#%dW zUVe{fcOZ{j<(Js=-ifr9JpG=XX<*{nX&!?m^kIO>l6W-52UL0rLH3ZIQAINDAJV>^io|v`H61O$`>@~?qc2r7G;w>ZF z_$B+vdjo^8I=S(YT4s_hf7+OqqtS29JRS4stDFbl7OC31fyJ!T-PM_)Qm?k<+E`wC zY~;hnfqP!+_#z^{RB{DAzjWls5Tl+Utq{7iss@=l`ux|!w|>X^b7R!;L8uE?7A!HB z;<<=D>X9h7dEDb?)qL26H8)al%~zQp1ijEnryPd|_>{le`7`#+8Q-7jpxCgcF0#B< z+FCaBY~^Kl$rtkKm<1Hv3okxVS6!#?Ovm1L(QNewzquLBnh(t*3#$KX{0}mt}OqW@Zq-#{y7L!d{XkSIbkii4XO)c z;7&JNVAQ2WiJrxe&`wwUYt#3ic|{FGIHnAq>NRfGtW!NwyH(TcO|eODgKbbbs14=` za9q#0)4R4$HFh&^XyMd?jIX#pZlcD%<)2sR?~&aed;#-Sq${1_!kYKVU2Ha~UMk>05 zk}~|rk8|qJiO&yF6n}+=>`gC{+sUiI2guK>1|Ws&_8;g)2w+|XZA|nnP8B)=-Yd$~ zI{!A#a(`$~r-S>%pV-_$4xmE9VMzq~hEGifXo}XoyzyoEZ&nT0Ct!i!L-Q1Py}pClnZ4x!+XpSE9A55RCx~=l zbo`DwJ{n)aNhJFTa) zO@p_hMk-GUJW?e4iZ#?*0Nd;%lG>lXk?@k>gHG|^TrqRpI0>h`q#cQ9TxH!7kAo?+vt@%MWd3e5Z zG+q9+R3s#3u;>Hg&W!)LKnp*o>n<-{m3c=!)8ge2Xo*VDWvFbS4W(Yy{)xYB*TAQv z``%TQHldV$gN1}$!)y^@(OkpY*_@0mILcf^ZFATu&#?Nw-Jd9B2cB0%xRWzgS%G(5 zD5&Ey(Hb^yQp19|w}qh&=~<(@CJoKY`VQ8VPE(wg2I+XYA(WMJm1+oX8}NP0g5Otg zw)!8nK%xT4&D{}D8f|0Oyw9jNf;76M;O*a?Wt!{jf`=Rb^xVmtM`d0bE!_4w>SOHR z(s-%k{51Tpv;Lb^$j@H}qVxQW9p`YNCT&fb4Trzxnp_>OJV;g zy1bxvC`}^uwN$YrkUY?J^wn{C_Nr)wvs;vPnysqGJY>qV_68N%j|TqLJG$AnU8u;y z5Iz@iFSq0MaXOsfiaQP`lsS&Ry{rop%Qxa zE{SY+G=IG1VQ8-@8wZvqX3c4i}+1Y$(tCs{z-IJ5%I>wtKLl8*g$@l5taV>7vnaKzkL=%J6! z6H8XX=GbGzUG9_0Q1@XIw-;V{5T<5;(0(4255`q!&bAaErR`Wrg)NOYbd zdf}nlXC=SOb#2Bl0zy^xs?w77Sshe6tHH31m0M&bctB&uG+{yzrpWg4kHtmEw&Nrp zfp*qh^EABB9=o`Tnqavc*C?iL?DRL>-}{~yIf{`rlw$~h#GI5NCeOu{O_rmOxi52VE1MdSdKZGr%EumEz>ya$WJUOz`G4UdR|5Q=A6E z^eQ@0s2Izr++WwOU1g ztQwHKcFuPAXqZ zd0Sq{f)?BUW}&3h{#JtYvCN{H9T3&lSP`ZuVf#3JH2*au_JbqP7IEEkrEnVZj|qYerRQ<8pU_uie3{Ww z5?WPLE97!~VG+4!%piHGmiW#@y9^QfP+NA? zJ|mdU#v4<^1U~i;okkio*ltmeD(fgX0YVjxcwJEE9}?<5QXQwk)fg4E8yf* z4Ov@RbGF7y1br2xq35TPlZc&k1St=fQNA}z#A{gWGeIQv5-WV6d{x5zSaxJ@{A&#( z<+cd4gLh2#m>Xba=0+z@6v)u%$-mxGMzX32(-$vwH&&_e-XvV>Om%W}NaM;3)mOW9 zA>r37$lf#Kn=@@+#1ZB2>}-o7l4aML*?W?ZFMQiC(`dKCYuTX<%Kr4Cg%FQc^MAYNo?(Zz_#p^}*%pWSf*k(;z)rh84AJ=cmS=frkk>(jf*D7pFEj7R0Rvd)WY zSLk3gi-CcN7$04J(o}vWm87@ulCwp8*BL*P_i9eo6gZ%9>RetZvxU{~gNu$l>Vqwi z(sghe_C~h%=ZN|a(q(=<6kuhw&jQuh>rU~>z0O`GhRq1?TRVHc5>@+}e2ZPns?Ou& zxHZBqRHCFSSob`dabVze_AdTQIp+q0`pDqWL%ZaW({hS#|A%IA7iEns_p6GytI6-q zOox5gGyLH`bl4WNy{gu5YF}+CZ&1mI9_9RXF7FOuzTsg!b%Y@^?9m4Gdc>R;{^bOz zzhdM+`Y~7FTdMmmpEkZU2(v@zd+$QR_wBCW@BMf|W>jlGb}(6F;3rS^6-KZ{l=BG9 z3)oKi)5T`-*LA~ESFYq+d0dM?xTlGVFYSHLhxEMeIV~X>)W?ow;2`V*$oc?Ubr^bn z?_WTlY!IyKTHCy#SLH@Y79QVn^}|$5E!_Oy0a$#Ej{WL!dXeGWY_L^mY8$pA<1q`_ zB4&gmd^_$=+)8Ssr#Sp69?KSf4`90g#ee^~eNcRYkNo>mU~-(6=>TH=xzU`LZ|lU* zwoLs_(wiNwZT9*pgp$(y-JLDIxIoAkk%pfGojs2rxZCLAv5|`J9Wwrnf|$u9@nIT9 zOm{TK`nku)7v?J0ijEr>%9^+kX>X{~MOtp4qvAZ8^&J_!FH9T%;*FWw5f-mK?QdQb zjmwLoKPpnR zLtdN_UiXO4dVA$2X*rh?-1-;nRwO6|*|iE51}G$7xE7+06|g15*^#tuxBAaIu>v|% zu;mfm7Qw3Mjj&`6!yS}@*jci**15;?eeL1ORA|oe2h_-3^Y)_BwgC<-C5b!4m94-q z@06_KW*TiJEh@(tR@BXvcNECB;Yy4B5suKD zV<7+&8_MyvXKI&fH>p&+N@vtOQ|6_k>&9?ywa2FPw|O*+Y3)N+J;iM?b2wPc47a76 zfNvLEImkTX69PB%O-f!-Q=d)*jPg~MGV?u~T6 zOM3h|V_tHN+29uw4+gQX`OPGO-{ClqH!fv1rKX5YXPJ6ExUiJRotuuq&cOTTZp_$# z`g-iT;@WElhkDl>QqDQxS(W7|} z(=cDMgpduN66dDoj7>u%le{Fp4srwrV*Q(JIE^hl_VaIqar}r(Jmxbie(_1AMV^40 zx{8p(v*QzF@FPXDI=P>L5jMZWyIX@zLWKKpa!=DJDUPK(2sXt6tw{H zMGzfpn@0oWU=gLU(X%io_f}L+hCnwNz$E9Q-}EC0K<1BHr>hJhk$zxw+HROGB0Z07 zZ3>>Y_(KM;vdClnZ=?R{Au8(N{-JVm@{iR|bKV^>Ari1CQm0|u>LW?jtb~+L>7DN; z_@t18>A?AZjvJ3d!QSz_fPZ{V@j%B%c61g_kUF(GbDfK3)Cd7%t-fcQ%gXTlLV< zZ&IO8oiDyUd0Q%XD~LOZP~)J?MoRZjyZLTS=_i*Hcuzno5bCqIa`8Wf==^z|Ie9zY z>wbU<&rW4i1H0v~zKLKk=2hwYHXRA;!=C1uGI6!ekn(fM{NEX?&kRkh(F6%cxMdP9 zAEV&BlAdw8v}rVlFe?og5<2a_s481<*?^0{aprUZ|Lv&O|9gWT-t^q!8*qo##l*$~ Ra1UMZv_S?M)oRb*{Rhv8?Na~% literal 0 HcmV?d00001 diff --git a/doc/source/user-guide/options.rst b/doc/source/user-guide/options.rst index 551dbfed0..98e001a8a 100644 --- a/doc/source/user-guide/options.rst +++ b/doc/source/user-guide/options.rst @@ -256,3 +256,90 @@ main ``index.rst`` file and the ``learning.rst`` file in its "Getting started" s To use this feature, you must have the `quarto ` package installed. To create thumbnails of generated PDF files, the theme is using `pdf2image`. So you should have the ``poppler`` package installed in your system. For more information, see the `pdf2image documentation `_. + +What's new section +------------------ + +The "What's new" section is an option that allows you to highlight new features in your library +for each minor version within the changelog file. + +To get started, create a YAML file named ``whatsnew.yml`` in the ``doc/source`` directory. The +YAML file should contain the following structure: + +.. code-block:: yaml + + fragments: + - title: Feature title + version: 0.2.0 # The version the feature is introduced + content: | + Feature description in RST format. + + - title: Another feature title + version: 0.1.2 + content: | + Feature description in RST format. + +The dropdown generation only supports the following RST formats in the "content" field: + +- Bold: Use double asterisks to wrap the text. +- Italics: Use single asterisks to wrap the text. +- Code samples: Use single or double backticks to wrap the text. +- Links: Use the following format to include links: + + .. code-block:: rst + + `link text `_ + +- Code blocks: Use the following format to include code blocks: + + .. code-block:: rst + + .. code:: python + + print("hello world") + +If a format is used in the "content" field that does not fall into the category above, it will not +be rendered correctly. + +To enable the "What's new" sections and sidebar in the changelog file, add the following dictionary +to the ``html_theme_options`` dictionary: + +.. code-block:: python + + html_theme_options = ( + { + "whatsnew": { + "no_of_headers": 3, + "no_of_contents": 3, + "whatsnew_file": "whatsnew", # Name of yaml file containing what's new content + "changelog_file": "changelog", # Name of changelog file (rst) + "pages": ["changelog", ...], + }, + }, + ) + +The dictionary contains the following keys: + +- ``no_of_headers``: Number of minor version sections to display in the what's new sidebar. + By default, it is set to 3. +- ``no_of_contents``: Number of what's new content to display under each minor version in the + what's new sidebar. By default, it is set to 3. +- ``whatsnew_file``: Name of the YAML file containing what's new content. The YAML file should be + in the ``doc/source`` directory. +- ``changelog_file``: Name of the changelog file (RST) located in the ``doc/source`` directory. +- ``pages``: List of names for the pages to include the what's new sidebar on. If no value is + provided, the what's new sidebar is only displayed in the changelog file. + +The following images show a sample "What's new" section and sidebar in the changelog file: + +.. tab-set:: + + .. tab-item:: What's new section + + .. image:: ../examples/images/whatsnew_section.png + :alt: What's new section + + .. tab-item:: What's new sidebar + + .. image:: ../examples/images/whatsnew_sidebar.png + :alt: What's new sidebar From 4d795b4802e444c44fc9d70cafda43f22e53d7ff Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Mon, 20 Jan 2025 14:02:11 -0500 Subject: [PATCH 55/73] fix doc build errors? --- .../whatsnew_section.png} | Bin .../whatsnew_sidebar.png} | Bin doc/source/user-guide/options.rst | 8 ++++---- 3 files changed, 4 insertions(+), 4 deletions(-) rename doc/source/{examples/images/whatsnew_section.PNG => _static/whatsnew_section.png} (100%) rename doc/source/{examples/images/whatsnew_sidebar.PNG => _static/whatsnew_sidebar.png} (100%) diff --git a/doc/source/examples/images/whatsnew_section.PNG b/doc/source/_static/whatsnew_section.png similarity index 100% rename from doc/source/examples/images/whatsnew_section.PNG rename to doc/source/_static/whatsnew_section.png diff --git a/doc/source/examples/images/whatsnew_sidebar.PNG b/doc/source/_static/whatsnew_sidebar.png similarity index 100% rename from doc/source/examples/images/whatsnew_sidebar.PNG rename to doc/source/_static/whatsnew_sidebar.png diff --git a/doc/source/user-guide/options.rst b/doc/source/user-guide/options.rst index 98e001a8a..20c621d5b 100644 --- a/doc/source/user-guide/options.rst +++ b/doc/source/user-guide/options.rst @@ -336,10 +336,10 @@ The following images show a sample "What's new" section and sidebar in the chang .. tab-item:: What's new section - .. image:: ../examples/images/whatsnew_section.png - :alt: What's new section + .. image:: ../_static/whatsnew_section.png + :alt: What's new section .. tab-item:: What's new sidebar - .. image:: ../examples/images/whatsnew_sidebar.png - :alt: What's new sidebar + .. image:: ../_static/whatsnew_sidebar.png + :alt: What's new sidebar From ac9232af3e62cc541b13d07abddf3ec73417fe6c Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Mon, 20 Jan 2025 16:37:58 -0500 Subject: [PATCH 56/73] skip whatsnew functions if section dne in conf.py --- src/ansys_sphinx_theme/__init__.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 4a33e30cb..89bbb6d68 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -596,6 +596,11 @@ def retrieve_whatsnew_input(app: Sphinx) -> tuple: def add_whatsnew_changelog(app, doctree): """Create doctree with minor version and what's new content.""" whatsnew_config = retrieve_whatsnew_input(app) + + # Skip this function if the whatsnew config is not found + if not whatsnew_config: + return + # Read the file and get the sections from the file as a list. For example, # sections = [
        ] sections = doctree.traverse(nodes.document) @@ -912,6 +917,10 @@ def extract_whatsnew(app, doctree, docname): """Extract the what's new content from the document.""" whatsnew_config = retrieve_whatsnew_input(app) + # Skip this function if the whatsnew config is not found + if not whatsnew_config: + return + if docname not in whatsnew_config["pages"]: return From df70429aae24943ceed7b4f92d00d1bf81ca17da Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 21 Jan 2025 10:52:18 -0500 Subject: [PATCH 57/73] don't filter number of content in what's new sidebar by default --- doc/source/user-guide/options.rst | 2 +- src/ansys_sphinx_theme/__init__.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/source/user-guide/options.rst b/doc/source/user-guide/options.rst index 20c621d5b..c07ff9596 100644 --- a/doc/source/user-guide/options.rst +++ b/doc/source/user-guide/options.rst @@ -323,7 +323,7 @@ The dictionary contains the following keys: - ``no_of_headers``: Number of minor version sections to display in the what's new sidebar. By default, it is set to 3. - ``no_of_contents``: Number of what's new content to display under each minor version in the - what's new sidebar. By default, it is set to 3. + what's new sidebar. By default, it displays all dropdowns. - ``whatsnew_file``: Name of the YAML file containing what's new content. The YAML file should be in the ``doc/source`` directory. - ``changelog_file``: Name of the changelog file (RST) located in the ``doc/source`` directory. diff --git a/src/ansys_sphinx_theme/__init__.py b/src/ansys_sphinx_theme/__init__.py index 89bbb6d68..ea04681d6 100644 --- a/src/ansys_sphinx_theme/__init__.py +++ b/src/ansys_sphinx_theme/__init__.py @@ -569,7 +569,7 @@ def retrieve_whatsnew_input(app: Sphinx) -> tuple: no_of_headers = whatsnew_options.get("no_of_headers", 3) # Get the number of what's new content to display under each minor version in the sidebar. # By default, it's 3 - no_of_contents = whatsnew_options.get("no_of_contents", 3) + no_of_contents = whatsnew_options.get("no_of_contents", None) # Get the name of the whatsnew.yml file in doc/source. By default, it's "whatsnew" whatsnew_file = whatsnew_options.get("whatsnew_file", "whatsnew") @@ -978,8 +978,9 @@ def extract_whatsnew(app, doctree, docname): # print("ids: ", ids) # Filter the displayed children based on the number of content specified in the config - if len(children) > whatsnew_config["no_of_contents"]: - children = children[: whatsnew_config["no_of_contents"]] + if whatsnew_config["no_of_contents"]: + if len(children) > whatsnew_config["no_of_contents"]: + children = children[: whatsnew_config["no_of_contents"]] contents = { "title": f"{html_title} {version_title}", From e58455fa0e320dc902ad81fc6723e5d1e98ad235 Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 21 Jan 2025 12:47:11 -0500 Subject: [PATCH 58/73] check if assets is defined --- src/ansys_sphinx_theme/theme/ansys_sphinx_theme/layout.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/layout.html b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/layout.html index c59cb3698..3b5a91ec9 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/layout.html +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/layout.html @@ -7,10 +7,12 @@ {% set assets = page_assets.get(pagename, {}) %} + {% if assets is defined and assets|length > 0 %} {% if assets.get("needs_datatables") %} {% endif %} + {% endif %} {% if theme_show_breadcrumbs %} @@ -36,6 +38,7 @@ {% set assets = page_assets.get(pagename, {}) %} + {% if assets is defined and assets|length > 0 %} {% if assets.get("needs_datatables") %} {% endif %} + {% endif %} {%- endblock %} From dadd2122a7a40fdd4db6a5c9edeb0a797220559f Mon Sep 17 00:00:00 2001 From: klmcadams <58492561+klmcadams@users.noreply.github.com> Date: Tue, 21 Jan 2025 13:22:49 -0500 Subject: [PATCH 59/73] check if page_assets are defined --- src/ansys_sphinx_theme/theme/ansys_sphinx_theme/layout.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/layout.html b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/layout.html index 3b5a91ec9..6e3f241ba 100644 --- a/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/layout.html +++ b/src/ansys_sphinx_theme/theme/ansys_sphinx_theme/layout.html @@ -6,8 +6,8 @@ + {% if page_assets is defined and page_assets|length > 0 %} {% set assets = page_assets.get(pagename, {}) %} - {% if assets is defined and assets|length > 0 %} {% if assets.get("needs_datatables") %} @@ -37,8 +37,8 @@ {{ super() }} + {% if page_assets is defined and page_assets|length > 0 %} {% set assets = page_assets.get(pagename, {}) %} - {% if assets is defined and assets|length > 0 %} {% if assets.get("needs_datatables") %}