From 0acc6c784794b8e2c0a345a989368feca22a99be Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Fri, 23 Jan 2026 15:31:56 +0100 Subject: [PATCH 01/15] Automatize API building --- docs/css/custom.css | 15 +++----- .../python/material/class.html.jinja | 37 +++++++++++++++++++ .../python/material/function.html.jinja | 37 +++++++++++++++++++ mkdocs.yml | 14 ++++++- requirements-docs.txt | 3 +- 5 files changed, 94 insertions(+), 12 deletions(-) diff --git a/docs/css/custom.css b/docs/css/custom.css index c09c2be371..806330d39b 100644 --- a/docs/css/custom.css +++ b/docs/css/custom.css @@ -171,24 +171,21 @@ /*******************************************************/ /* Fix z-index. */ -header.md-header { - z-index: 900 !important; +.md-overlay { + z-index: 800 !important; } .md-sidebar { - z-index: 1000 !important; + z-index: 900 !important; } -.md-overlay { - z-index: 950 !important; +header.md-header { + z-index: 1000 !important; } .md-search__overlay { z-index: 1100 !important; } -.md-search__form { +.md-search__inner { z-index: 1200 !important; } -.md-search__output { - z-index: 1100 !important; -} /*******************************************************/ /* Hide repo stats. */ diff --git a/docs/templates/python/material/class.html.jinja b/docs/templates/python/material/class.html.jinja index 40687fccf1..1ee1faa2bc 100644 --- a/docs/templates/python/material/class.html.jinja +++ b/docs/templates/python/material/class.html.jinja @@ -1,6 +1,24 @@ {% extends "_base/class.html.jinja" %} {% block heading scoped %} + {% block alias_anchors scoped %} + {% if class.hopsworks_aliases and class.hopsworks_aliases.aliases %} + {% for alias in class.hopsworks_aliases.aliases -%} + {% for path in alias.paths -%} + {%- set alias_id = path + "." + (alias.as_alias or alias.object_name) -%} + {% filter heading( + heading_level, + role="class", + id=alias_id, + class="doc doc-heading", + hidden=true, + skip_inventory=config.skip_local_inventory, + ) -%}{%- endfilter %} + {%- endfor %} + {%- endfor %} + {% endif %} + {% endblock alias_anchors %} + {% block source_link scoped %} {% if config.extra.link_source and class.source_link %} [source] @@ -10,3 +28,22 @@ {{ super() }} {% endblock heading %} + +{% block contents scoped %} + {% block aliases scoped %} + {% if class.hopsworks_aliases and class.hopsworks_aliases.aliases %} +

+ Aliases: {% for alias in class.hopsworks_aliases.aliases -%} + {% for path in alias.paths -%} + {%- set fullpath = path + "." + (alias.as_alias or alias.object_name) -%} + {{fullpath}} + {%- if not loop.last %}, {% endif %} + {%- endfor %} + {%- if not loop.last %}, {% endif %} + {%- endfor %} +

+ {% endif %} + {% endblock aliases %} + + {{ super() }} +{% endblock contents %} diff --git a/docs/templates/python/material/function.html.jinja b/docs/templates/python/material/function.html.jinja index 7d621a25e3..2a41f81db1 100644 --- a/docs/templates/python/material/function.html.jinja +++ b/docs/templates/python/material/function.html.jinja @@ -1,6 +1,24 @@ {% extends "_base/function.html.jinja" %} {% block heading scoped %} + {% block alias_anchors scoped %} + {% if function.hopsworks_aliases and function.hopsworks_aliases.aliases %} + {% for alias in function.hopsworks_aliases.aliases -%} + {% for path in alias.paths -%} + {%- set alias_id = path + "." + (alias.as_alias or alias.object_name) -%} + {% filter heading( + heading_level, + role="function", + id=alias_id, + class="doc doc-heading", + hidden=true, + skip_inventory=config.skip_local_inventory, + ) -%}{%- endfilter %} + {%- endfor %} + {%- endfor %} + {% endif %} + {% endblock alias_anchors %} + {% block source_link scoped %} {% if config.extra.link_source and function.source_link %} [source] @@ -10,3 +28,22 @@ {{ super() }} {% endblock heading %} + +{% block contents scoped %} + {% block aliases scoped %} + {% if function.hopsworks_aliases and function.hopsworks_aliases.aliases %} +

+ Aliases: {% for alias in function.hopsworks_aliases.aliases -%} + {% for path in alias.paths -%} + {%- set fullpath = path + "." + (alias.as_alias or alias.object_name) -%} + {{fullpath}} + {%- if not loop.last %}, {% endif %} + {%- endfor %} + {%- if not loop.last %}, {% endif %} + {%- endfor %} +

+ {% endif %} + {% endblock aliases %} + + {{ super() }} +{% endblock contents %} diff --git a/mkdocs.yml b/mkdocs.yml index 474307ba1e..567c52edf7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -264,7 +264,7 @@ nav: - Access Audit Logs: setup_installation/admin/audit/audit-logs.md - Export Audit Logs: setup_installation/admin/audit/export-audit-logs.md - ArrowFlight Server with DuckDB: setup_installation/common/arrow_flight_duckdb.md - - Python API: "!import https://github.com/logicalclocks/hopsworks-api?branch=main" + - Python API: python-api - Java API: javadoc - Community ↗: https://community.hopsworks.ai/ @@ -333,7 +333,15 @@ plugins: minify_js: true - mike: canonical_version: latest - - multirepo + - api-autonav: + modules: + - hopsworks + - hopsworks_common + - hsfs + - hsml + nav_section_title: Python API + api_root_uri: python-api + hide_empty: true - mkdocstrings: custom_templates: docs/templates handlers: @@ -351,6 +359,8 @@ plugins: annotations_path: source extra: link_source: true + extensions: + - hopsworks_aliases.extension inventories: - https://docs.python.org/3/objects.inv - https://pandas.pydata.org/docs/objects.inv diff --git a/requirements-docs.txt b/requirements-docs.txt index e3e38fea15..6ccf073ddd 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -4,7 +4,8 @@ mike==2.1.3 markdown==3.9 pymdown-extensions==10.17.2 mkdocs-minify-plugin>=0.2.0 -mkdocs-multirepo-plugin==0.8.3 +mkdocs-api-autonav@git+https://github.com/aversey/mkdocs-api-autonav.git +hopsworks-aliases@git+https://github.com/aversey/hopsworks-aliases.git mkdocstrings[python]==1.0.0 mkdocstrings-python==2.0.1 linkchecker From 82b638b6ab7a4da6bb691b17d2ca5157e5a19091 Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Tue, 27 Jan 2026 14:35:11 +0100 Subject: [PATCH 02/15] Show only public entities --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index 567c52edf7..50071e2510 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -357,6 +357,7 @@ plugins: show_source: false docstring_section_style: spacy annotations_path: source + filters: public extra: link_source: true extensions: From f6edd029c37e62afc09bce682fcc61b05df4213b Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Wed, 4 Feb 2026 12:38:43 +0100 Subject: [PATCH 03/15] Show public aliases --- .../python/material/class.html.jinja | 35 ++++++++----------- .../python/material/function.html.jinja | 35 ++++++++----------- mkdocs.yml | 8 ++--- requirements-docs.txt | 3 +- 4 files changed, 35 insertions(+), 46 deletions(-) diff --git a/docs/templates/python/material/class.html.jinja b/docs/templates/python/material/class.html.jinja index 1ee1faa2bc..5820ed5a52 100644 --- a/docs/templates/python/material/class.html.jinja +++ b/docs/templates/python/material/class.html.jinja @@ -2,19 +2,17 @@ {% block heading scoped %} {% block alias_anchors scoped %} - {% if class.hopsworks_aliases and class.hopsworks_aliases.aliases %} - {% for alias in class.hopsworks_aliases.aliases -%} - {% for path in alias.paths -%} - {%- set alias_id = path + "." + (alias.as_alias or alias.object_name) -%} - {% filter heading( - heading_level, - role="class", - id=alias_id, - class="doc doc-heading", - hidden=true, - skip_inventory=config.skip_local_inventory, - ) -%}{%- endfilter %} - {%- endfor %} + {% if class.extra.hopsworks_apigen and class.extra.hopsworks_apigen.aliases %} + {% for alias in class.extra.hopsworks_apigen.aliases if alias.is_public -%} + {%- set alias_id = alias.target_module + "." + alias.alias_name -%} + {% filter heading( + heading_level+9, + role="class", + id=alias_id, + class="doc doc-heading", + hidden=true, + skip_inventory=config.skip_local_inventory, + ) -%}{%- endfilter %} {%- endfor %} {% endif %} {% endblock alias_anchors %} @@ -31,14 +29,11 @@ {% block contents scoped %} {% block aliases scoped %} - {% if class.hopsworks_aliases and class.hopsworks_aliases.aliases %} + {% if class.extra.hopsworks_apigen and class.extra.hopsworks_apigen.aliases %}

- Aliases: {% for alias in class.hopsworks_aliases.aliases -%} - {% for path in alias.paths -%} - {%- set fullpath = path + "." + (alias.as_alias or alias.object_name) -%} - {{fullpath}} - {%- if not loop.last %}, {% endif %} - {%- endfor %} + Aliases: {% for alias in class.extra.hopsworks_apigen.aliases if alias.is_public -%} + {%- set fullpath = alias.target_module + "." + alias.alias_name -%} + {{fullpath}} {%- if not loop.last %}, {% endif %} {%- endfor %}

diff --git a/docs/templates/python/material/function.html.jinja b/docs/templates/python/material/function.html.jinja index 2a41f81db1..e940070d21 100644 --- a/docs/templates/python/material/function.html.jinja +++ b/docs/templates/python/material/function.html.jinja @@ -2,19 +2,17 @@ {% block heading scoped %} {% block alias_anchors scoped %} - {% if function.hopsworks_aliases and function.hopsworks_aliases.aliases %} - {% for alias in function.hopsworks_aliases.aliases -%} - {% for path in alias.paths -%} - {%- set alias_id = path + "." + (alias.as_alias or alias.object_name) -%} - {% filter heading( - heading_level, - role="function", - id=alias_id, - class="doc doc-heading", - hidden=true, - skip_inventory=config.skip_local_inventory, - ) -%}{%- endfilter %} - {%- endfor %} + {% if function.extra.hopsworks_apigen and function.extra.hopsworks_apigen.aliases %} + {% for alias in function.extra.hopsworks_apigen.aliases if alias.is_public -%} + {%- set alias_id = alias.target_module + "." + alias.alias_name -%} + {% filter heading( + heading_level+9, + role="function", + id=alias_id, + class="doc doc-heading", + hidden=true, + skip_inventory=config.skip_local_inventory, + ) -%}{%- endfilter %} {%- endfor %} {% endif %} {% endblock alias_anchors %} @@ -31,14 +29,11 @@ {% block contents scoped %} {% block aliases scoped %} - {% if function.hopsworks_aliases and function.hopsworks_aliases.aliases %} + {% if function.extra.hopsworks_apigen and function.extra.hopsworks_apigen.aliases %}

- Aliases: {% for alias in function.hopsworks_aliases.aliases -%} - {% for path in alias.paths -%} - {%- set fullpath = path + "." + (alias.as_alias or alias.object_name) -%} - {{fullpath}} - {%- if not loop.last %}, {% endif %} - {%- endfor %} + Aliases: {% for alias in function.extra.hopsworks_apigen.aliases if alias.is_public -%} + {%- set fullpath = alias.target_module + "." + alias.alias_name -%} + {{fullpath}} {%- if not loop.last %}, {% endif %} {%- endfor %}

diff --git a/mkdocs.yml b/mkdocs.yml index 50071e2510..0758f36b67 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -333,15 +333,14 @@ plugins: minify_js: true - mike: canonical_version: latest - - api-autonav: + - hopsworks-apigen: modules: - - hopsworks - hopsworks_common - hsfs - hsml + - hopsworks nav_section_title: Python API api_root_uri: python-api - hide_empty: true - mkdocstrings: custom_templates: docs/templates handlers: @@ -354,6 +353,7 @@ plugins: signature_crossrefs: true show_symbol_type_heading: true show_symbol_type_toc: true + members_order: source show_source: false docstring_section_style: spacy annotations_path: source @@ -361,7 +361,7 @@ plugins: extra: link_source: true extensions: - - hopsworks_aliases.extension + - hopsworks_apigen.mkdocs inventories: - https://docs.python.org/3/objects.inv - https://pandas.pydata.org/docs/objects.inv diff --git a/requirements-docs.txt b/requirements-docs.txt index 6ccf073ddd..426d9e4724 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -4,8 +4,7 @@ mike==2.1.3 markdown==3.9 pymdown-extensions==10.17.2 mkdocs-minify-plugin>=0.2.0 -mkdocs-api-autonav@git+https://github.com/aversey/mkdocs-api-autonav.git -hopsworks-aliases@git+https://github.com/aversey/hopsworks-aliases.git +hopsworks-apigen@git+https://github.com/aversey/hopsworks-aliases.git mkdocstrings[python]==1.0.0 mkdocstrings-python==2.0.1 linkchecker From 9cf2c3bf0f053df716b755927c0c8b19e851d813 Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Wed, 4 Feb 2026 12:40:58 +0100 Subject: [PATCH 04/15] Skip the primary alias --- .../python/material/class.html.jinja | 28 +++++++++++-------- .../python/material/function.html.jinja | 28 +++++++++++-------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/docs/templates/python/material/class.html.jinja b/docs/templates/python/material/class.html.jinja index 5820ed5a52..4b4af7d639 100644 --- a/docs/templates/python/material/class.html.jinja +++ b/docs/templates/python/material/class.html.jinja @@ -4,15 +4,17 @@ {% block alias_anchors scoped %} {% if class.extra.hopsworks_apigen and class.extra.hopsworks_apigen.aliases %} {% for alias in class.extra.hopsworks_apigen.aliases if alias.is_public -%} - {%- set alias_id = alias.target_module + "." + alias.alias_name -%} - {% filter heading( - heading_level+9, - role="class", - id=alias_id, - class="doc doc-heading", - hidden=true, - skip_inventory=config.skip_local_inventory, - ) -%}{%- endfilter %} + {% if not loop.first %} + {%- set alias_id = alias.target_module + "." + alias.alias_name -%} + {% filter heading( + heading_level+9, + role="class", + id=alias_id, + class="doc doc-heading", + hidden=true, + skip_inventory=config.skip_local_inventory, + ) -%}{%- endfilter %} + {% endif %} {%- endfor %} {% endif %} {% endblock alias_anchors %} @@ -32,9 +34,11 @@ {% if class.extra.hopsworks_apigen and class.extra.hopsworks_apigen.aliases %}

Aliases: {% for alias in class.extra.hopsworks_apigen.aliases if alias.is_public -%} - {%- set fullpath = alias.target_module + "." + alias.alias_name -%} - {{fullpath}} - {%- if not loop.last %}, {% endif %} + {% if not loop.first %} + {%- set fullpath = alias.target_module + "." + alias.alias_name -%} + {{fullpath}} + {%- if not loop.last %}, {% endif %} + {% endif %} {%- endfor %}

{% endif %} diff --git a/docs/templates/python/material/function.html.jinja b/docs/templates/python/material/function.html.jinja index e940070d21..a202f09730 100644 --- a/docs/templates/python/material/function.html.jinja +++ b/docs/templates/python/material/function.html.jinja @@ -4,15 +4,17 @@ {% block alias_anchors scoped %} {% if function.extra.hopsworks_apigen and function.extra.hopsworks_apigen.aliases %} {% for alias in function.extra.hopsworks_apigen.aliases if alias.is_public -%} - {%- set alias_id = alias.target_module + "." + alias.alias_name -%} - {% filter heading( - heading_level+9, - role="function", - id=alias_id, - class="doc doc-heading", - hidden=true, - skip_inventory=config.skip_local_inventory, - ) -%}{%- endfilter %} + {% if not loop.first %} + {%- set alias_id = alias.target_module + "." + alias.alias_name -%} + {% filter heading( + heading_level+9, + role="function", + id=alias_id, + class="doc doc-heading", + hidden=true, + skip_inventory=config.skip_local_inventory, + ) -%}{%- endfilter %} + {% endif %} {%- endfor %} {% endif %} {% endblock alias_anchors %} @@ -32,9 +34,11 @@ {% if function.extra.hopsworks_apigen and function.extra.hopsworks_apigen.aliases %}

Aliases: {% for alias in function.extra.hopsworks_apigen.aliases if alias.is_public -%} - {%- set fullpath = alias.target_module + "." + alias.alias_name -%} - {{fullpath}} - {%- if not loop.last %}, {% endif %} + {% if not loop.first %} + {%- set fullpath = alias.target_module + "." + alias.alias_name -%} + {{fullpath}} + {%- if not loop.last %}, {% endif %} + {% endif %} {%- endfor %}

{% endif %} From b98b683a0f144c9d8a494bbe8f99020adf4a12f6 Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Wed, 4 Feb 2026 12:55:18 +0100 Subject: [PATCH 05/15] Fix TOC --- .../python/material/class.html.jinja | 36 +++++++++---------- .../python/material/function.html.jinja | 36 +++++++++---------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/docs/templates/python/material/class.html.jinja b/docs/templates/python/material/class.html.jinja index 4b4af7d639..17f6947347 100644 --- a/docs/templates/python/material/class.html.jinja +++ b/docs/templates/python/material/class.html.jinja @@ -3,18 +3,17 @@ {% block heading scoped %} {% block alias_anchors scoped %} {% if class.extra.hopsworks_apigen and class.extra.hopsworks_apigen.aliases %} - {% for alias in class.extra.hopsworks_apigen.aliases if alias.is_public -%} - {% if not loop.first %} - {%- set alias_id = alias.target_module + "." + alias.alias_name -%} - {% filter heading( - heading_level+9, - role="class", - id=alias_id, - class="doc doc-heading", - hidden=true, - skip_inventory=config.skip_local_inventory, - ) -%}{%- endfilter %} - {% endif %} + {%- set public_aliases = class.extra.hopsworks_apigen.aliases | selectattr("is_public") | list -%} + {% for alias in public_aliases[1:] -%} + {%- set alias_id = alias.target_module + "." + alias.alias_name -%} + {% filter heading( + 9, + role="class", + id=alias_id, + class="doc doc-heading", + hidden=true, + skip_inventory=config.skip_local_inventory, + ) -%}{%- endfilter %} {%- endfor %} {% endif %} {% endblock alias_anchors %} @@ -32,15 +31,16 @@ {% block contents scoped %} {% block aliases scoped %} {% if class.extra.hopsworks_apigen and class.extra.hopsworks_apigen.aliases %} -

- Aliases: {% for alias in class.extra.hopsworks_apigen.aliases if alias.is_public -%} - {% if not loop.first %} + {%- set public_aliases = class.extra.hopsworks_apigen.aliases | selectattr("is_public") | list -%} + {% if public_aliases and public_aliases[1:] %} +

+ Aliases: {% for alias in public_aliases[1:] -%} {%- set fullpath = alias.target_module + "." + alias.alias_name -%} {{fullpath}} {%- if not loop.last %}, {% endif %} - {% endif %} - {%- endfor %} -

+ {%- endfor %} +

+ {% endif %} {% endif %} {% endblock aliases %} diff --git a/docs/templates/python/material/function.html.jinja b/docs/templates/python/material/function.html.jinja index a202f09730..0462ff6fa3 100644 --- a/docs/templates/python/material/function.html.jinja +++ b/docs/templates/python/material/function.html.jinja @@ -3,18 +3,17 @@ {% block heading scoped %} {% block alias_anchors scoped %} {% if function.extra.hopsworks_apigen and function.extra.hopsworks_apigen.aliases %} - {% for alias in function.extra.hopsworks_apigen.aliases if alias.is_public -%} - {% if not loop.first %} - {%- set alias_id = alias.target_module + "." + alias.alias_name -%} - {% filter heading( - heading_level+9, - role="function", - id=alias_id, - class="doc doc-heading", - hidden=true, - skip_inventory=config.skip_local_inventory, - ) -%}{%- endfilter %} - {% endif %} + {%- set public_aliases = function.extra.hopsworks_apigen.aliases | selectattr("is_public") | list -%} + {% for alias in public_aliases[1:] -%} + {%- set alias_id = alias.target_module + "." + alias.alias_name -%} + {% filter heading( + 9, + role="function", + id=alias_id, + class="doc doc-heading", + hidden=true, + skip_inventory=config.skip_local_inventory, + ) -%}{%- endfilter %} {%- endfor %} {% endif %} {% endblock alias_anchors %} @@ -32,15 +31,16 @@ {% block contents scoped %} {% block aliases scoped %} {% if function.extra.hopsworks_apigen and function.extra.hopsworks_apigen.aliases %} -

- Aliases: {% for alias in function.extra.hopsworks_apigen.aliases if alias.is_public -%} - {% if not loop.first %} + {%- set public_aliases = function.extra.hopsworks_apigen.aliases | selectattr("is_public") | list -%} + {% if public_aliases and public_aliases[1:] %} +

+ Aliases: {% for alias in public_aliases[1:] -%} {%- set fullpath = alias.target_module + "." + alias.alias_name -%} {{fullpath}} {%- if not loop.last %}, {% endif %} - {% endif %} - {%- endfor %} -

+ {%- endfor %} +

+ {% endif %} {% endif %} {% endblock aliases %} From 55452914786b505126c6d422561c89e1fbc1befd Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Wed, 4 Feb 2026 13:09:28 +0100 Subject: [PATCH 06/15] Fix anchors --- docs/templates/python/material/class.html.jinja | 3 +-- docs/templates/python/material/function.html.jinja | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/templates/python/material/class.html.jinja b/docs/templates/python/material/class.html.jinja index 17f6947347..025bcfc1d3 100644 --- a/docs/templates/python/material/class.html.jinja +++ b/docs/templates/python/material/class.html.jinja @@ -3,8 +3,7 @@ {% block heading scoped %} {% block alias_anchors scoped %} {% if class.extra.hopsworks_apigen and class.extra.hopsworks_apigen.aliases %} - {%- set public_aliases = class.extra.hopsworks_apigen.aliases | selectattr("is_public") | list -%} - {% for alias in public_aliases[1:] -%} + {% for alias in class.extra.hopsworks_apigen.aliases -%} {%- set alias_id = alias.target_module + "." + alias.alias_name -%} {% filter heading( 9, diff --git a/docs/templates/python/material/function.html.jinja b/docs/templates/python/material/function.html.jinja index 0462ff6fa3..c6c494d542 100644 --- a/docs/templates/python/material/function.html.jinja +++ b/docs/templates/python/material/function.html.jinja @@ -3,8 +3,7 @@ {% block heading scoped %} {% block alias_anchors scoped %} {% if function.extra.hopsworks_apigen and function.extra.hopsworks_apigen.aliases %} - {%- set public_aliases = function.extra.hopsworks_apigen.aliases | selectattr("is_public") | list -%} - {% for alias in public_aliases[1:] -%} + {% for alias in function.extra.hopsworks_apigen.aliases -%} {%- set alias_id = alias.target_module + "." + alias.alias_name -%} {% filter heading( 9, From c282e617e47112ca56cdc1f0ba0df18a33a4dc8b Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Fri, 6 Feb 2026 15:31:53 +0100 Subject: [PATCH 07/15] Add ruff and respect aliases of methods too --- docs/templates/python/material/function.html.jinja | 13 +++++++++++++ requirements-docs.txt | 1 + 2 files changed, 14 insertions(+) diff --git a/docs/templates/python/material/function.html.jinja b/docs/templates/python/material/function.html.jinja index c6c494d542..494f3e379f 100644 --- a/docs/templates/python/material/function.html.jinja +++ b/docs/templates/python/material/function.html.jinja @@ -15,6 +15,19 @@ ) -%}{%- endfilter %} {%- endfor %} {% endif %} + {% if function.parent and function.parent.extra.hopsworks_apigen and function.parent.extra.hopsworks_apigen.aliases %} + {% for alias in function.parent.extra.hopsworks_apigen.aliases -%} + {%- set alias_id = alias.target_module + "." + alias.alias_name + "." + function.name -%} + {% filter heading( + 9, + role="function", + id=alias_id, + class="doc doc-heading", + hidden=true, + skip_inventory=config.skip_local_inventory, + ) -%}{%- endfilter %} + {%- endfor %} + {% endif %} {% endblock alias_anchors %} {% block source_link scoped %} diff --git a/requirements-docs.txt b/requirements-docs.txt index 426d9e4724..ad8d20e1e0 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -7,4 +7,5 @@ mkdocs-minify-plugin>=0.2.0 hopsworks-apigen@git+https://github.com/aversey/hopsworks-aliases.git mkdocstrings[python]==1.0.0 mkdocstrings-python==2.0.1 +ruff==0.15.0 linkchecker From df9aa9657888b4e90517efab1bdca0a1c015a22d Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Mon, 16 Feb 2026 11:31:48 +0100 Subject: [PATCH 08/15] Publish my version of API --- .github/workflows/mkdocs-release.yml | 2 +- .github/workflows/mkdocs-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mkdocs-release.yml b/.github/workflows/mkdocs-release.yml index 63ffc0f23f..4a751fc7d7 100644 --- a/.github/workflows/mkdocs-release.yml +++ b/.github/workflows/mkdocs-release.yml @@ -59,7 +59,7 @@ jobs: - name: Checkout the API repo uses: actions/checkout@v4 with: - repository: logicalclocks/hopsworks-api + repository: aversey/hopsworks-api ref: ${{ env.BRANCH }} path: hopsworks-api diff --git a/.github/workflows/mkdocs-test.yml b/.github/workflows/mkdocs-test.yml index fa2c942f10..93a8527f61 100644 --- a/.github/workflows/mkdocs-test.yml +++ b/.github/workflows/mkdocs-test.yml @@ -15,7 +15,7 @@ jobs: - name: Checkout the API repo uses: actions/checkout@v4 with: - repository: logicalclocks/hopsworks-api + repository: aversey/hopsworks-api ref: ${{ github.base_ref }} path: hopsworks-api From 407f126e309379d0bb2733ace18ead55fe7e9a6a Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Tue, 17 Feb 2026 15:45:26 +0100 Subject: [PATCH 09/15] Add returned-by and hide empty attribute signatures --- docs/css/custom.css | 12 + .../python/material/attribute.html.jinja | 134 +++++- .../python/material/backlinks.html.jinja | 25 ++ .../python/material/class.html.jinja | 383 ++++++++++++++++-- .../python/material/function.html.jinja | 261 +++++++++--- .../python/material/module.html.jinja | 135 +++++- mkdocs.yml | 2 + requirements-docs.txt | 7 +- 8 files changed, 849 insertions(+), 110 deletions(-) create mode 100644 docs/templates/python/material/backlinks.html.jinja diff --git a/docs/css/custom.css b/docs/css/custom.css index 806330d39b..26f7a273cf 100644 --- a/docs/css/custom.css +++ b/docs/css/custom.css @@ -193,6 +193,18 @@ header.md-header { display: none; } +/*******************************************************/ +/* Hide empty backlinks. */ +.info-backlinks:has(.doc-backlink-list:empty) { + display: none; +} + +/*******************************************************/ +/* Hide symbol type labels from backlinks. */ +.doc-backlink-crumb .doc-symbol { + display: none; +} + /*******************************************************/ /* Custom styles for syntax highlighting in signatures. */ diff --git a/docs/templates/python/material/attribute.html.jinja b/docs/templates/python/material/attribute.html.jinja index 97eb8ebe34..f5d1fe083e 100644 --- a/docs/templates/python/material/attribute.html.jinja +++ b/docs/templates/python/material/attribute.html.jinja @@ -1,12 +1,130 @@ -{% extends "_base/attribute.html.jinja" %} +{#- Template for Python attributes. -{% block heading scoped %} - {% block source_link scoped %} - {% if config.extra.link_source and attribute.source_link %} - [source] +This template renders a Python attribute (or variable). +This can be a module attribute or a class attribute. + +Context: + attribute (griffe.Attribute): The attribute to render. + root (bool): Whether this is the root object, injected with `:::` in a Markdown page. + heading_level (int): The HTML heading level to use. + config (dict): The configuration options. +-#} + +{% block logs scoped %} + {#- Logging block. + + This block can be used to log debug messages, deprecation messages, warnings, etc. + -#} + {{ log.debug("Rendering " + attribute.path) }} +{% endblock logs %} + +
+ {% with obj = attribute, html_id = attribute.path %} + + {% if root %} + {% set show_full_path = config.show_root_full_path %} + {% set root_members = True %} + {% elif root_members %} + {% set show_full_path = config.show_root_members_full_path or config.show_object_full_path %} + {% set root_members = False %} + {% else %} + {% set show_full_path = config.show_object_full_path %} + {% endif %} + + {% set attribute_name = attribute.path if show_full_path else attribute.name %} + + {% if not root or config.show_root_heading %} + {% filter heading( + heading_level, + role="data" if attribute.parent.kind.value == "module" else "attr", + id=html_id, + class="doc doc-heading", + toc_label=(' '|safe if config.show_symbol_type_toc else '') + (config.toc_label if config.toc_label and root else attribute.name), + skip_inventory=config.skip_local_inventory, + ) %} + + {% block heading scoped %} + {#- Heading block. + + This block renders the heading for the attribute. + -#} + {% block source_link scoped %} + {% if config.extra.link_source and attribute.source_link %} + [source] + {% endif %} + {% endblock source_link %} + + {% if config.show_symbol_type_heading %}{% endif %} + {% if config.heading and root %} + {{ config.heading }} + {% elif config.separate_signature %} + {{ attribute_name }} + {% else %} + {%+ filter highlight(language="python", inline=True) %} + {{ attribute_name }}{% if attribute.annotation and config.show_signature_annotations %}: {{ attribute.annotation }}{% endif %} + {% if config.show_attribute_values and attribute.value %} = {{ attribute.value }}{% endif %} + {% endfilter %} + {% endif %} + {% endblock heading %} + + {% block labels scoped %} + {#- Labels block. + + This block renders the labels for the attribute. + -#} + {% with labels = attribute.labels %} + {% include "labels.html.jinja" with context %} + {% endwith %} + {% endblock labels %} + + {% endfilter %} + + {% block signature scoped %} + {#- Signature block. + + This block renders the signature for the attribute. + -#} + {% if config.separate_signature and (attribute.value or attribute.annotation) %} + {% filter format_attribute(attribute, config.line_length, crossrefs=config.signature_crossrefs, show_value=config.show_attribute_values) %} + {{ attribute.name }} + {% endfilter %} + {% endif %} + {% endblock signature %} + + {% else %} + + {% if config.show_root_toc_entry %} + {% filter heading(heading_level, + role="data" if attribute.parent.kind.value == "module" else "attr", + id=html_id, + toc_label=(' '|safe if config.show_symbol_type_toc else '') + (config.toc_label if config.toc_label and root else attribute_name), + hidden=True, + skip_inventory=config.skip_local_inventory, + ) %} + {% endfilter %} + {% endif %} + {% set heading_level = heading_level - 1 %} {% endif %} - {% endblock source_link %} - {{ super() }} +
+ {% block contents scoped %} + {#- Contents block. + + This block renders the contents of the attribute. + It contains other blocks that users can override. + Overriding the contents block allows to rearrange the order of the blocks. + -#} + {% block docstring scoped %} + {#- Docstring block. + + This block renders the docstring for the attribute. + -#} + {% with docstring_sections = attribute.docstring.parsed %} + {% include "docstring.html.jinja" with context %} + {% endwith %} + {% endblock docstring %} + {% endblock contents %} +
-{% endblock heading %} + {% endwith %} +
diff --git a/docs/templates/python/material/backlinks.html.jinja b/docs/templates/python/material/backlinks.html.jinja new file mode 100644 index 0000000000..ecbfa2cac2 --- /dev/null +++ b/docs/templates/python/material/backlinks.html.jinja @@ -0,0 +1,25 @@ +{#- Template for backlinks. + +This template renders backlinks. + +Context: + backlinks (Mapping[str, Iterable[str]]): The backlinks to render. + config (dict): The configuration options. + verbose_type (Mapping[str, str]): The verbose backlink types. + default_crumb (BacklinkCrumb): A default, empty crumb. +-#} + +{% macro render_crumb(crumb) %} + + {% if crumb.url and crumb.title %} + {{ crumb.parent.title | replace(" ", "") | safe }}.{{ crumb.title | replace(" ", "") | safe }} + {% endif %} + +{% endmacro %} + + +{%- for backlink in backlinks["returned-by"] | sort(attribute="crumbs") -%} + +{%- endfor -%} diff --git a/docs/templates/python/material/class.html.jinja b/docs/templates/python/material/class.html.jinja index 025bcfc1d3..ed20289083 100644 --- a/docs/templates/python/material/class.html.jinja +++ b/docs/templates/python/material/class.html.jinja @@ -1,47 +1,350 @@ -{% extends "_base/class.html.jinja" %} - -{% block heading scoped %} - {% block alias_anchors scoped %} - {% if class.extra.hopsworks_apigen and class.extra.hopsworks_apigen.aliases %} - {% for alias in class.extra.hopsworks_apigen.aliases -%} - {%- set alias_id = alias.target_module + "." + alias.alias_name -%} - {% filter heading( - 9, +{#- Template for Python classes. + +This template renders a Python class. + +Context: + class (griffe.Class): The class to render. + root (bool): Whether this is the root object, injected with `:::` in a Markdown page. + heading_level (int): The HTML heading level to use. + config (dict): The configuration options. +-#} + +{% block logs scoped %} + {#- Logging block. + + This block can be used to log debug messages, deprecation messages, warnings, etc. + -#} + {{ log.debug("Rendering " + class.path) }} +{% endblock logs %} + +{% import "language.html.jinja" as lang with context %} +{#- Language module providing the `t` translation method. -#} + +
+ {% with obj = class, html_id = class.path, all_members = class.all_members %} + + {% if root %} + {% set show_full_path = config.show_root_full_path %} + {% set root_members = True %} + {% elif root_members %} + {% set show_full_path = config.show_root_members_full_path or config.show_object_full_path %} + {% set root_members = False %} + {% else %} + {% set show_full_path = config.show_object_full_path %} + {% endif %} + + {% set class_name = class.path if show_full_path else class.name %} + + {% if not root or config.show_root_heading %} + {% filter heading( + heading_level, role="class", - id=alias_id, + id=html_id, class="doc doc-heading", - hidden=true, + toc_label=(' '|safe if config.show_symbol_type_toc else '') + (config.toc_label if config.toc_label and root else class.name), skip_inventory=config.skip_local_inventory, - ) -%}{%- endfilter %} - {%- endfor %} - {% endif %} - {% endblock alias_anchors %} + ) %} - {% block source_link scoped %} - {% if config.extra.link_source and class.source_link %} - [source] - {% endif %} - {% endblock source_link %} - - {{ super() }} - -{% endblock heading %} - -{% block contents scoped %} - {% block aliases scoped %} - {% if class.extra.hopsworks_apigen and class.extra.hopsworks_apigen.aliases %} - {%- set public_aliases = class.extra.hopsworks_apigen.aliases | selectattr("is_public") | list -%} - {% if public_aliases and public_aliases[1:] %} -

- Aliases: {% for alias in public_aliases[1:] -%} - {%- set fullpath = alias.target_module + "." + alias.alias_name -%} - {{fullpath}} - {%- if not loop.last %}, {% endif %} - {%- endfor %} -

+ {% block heading scoped %} + {#- Heading block. + + This block renders the heading for the class. + -#} + {% block alias_anchors scoped %} + {% if class.extra.hopsworks_apigen and class.extra.hopsworks_apigen.aliases %} + {% for alias in class.extra.hopsworks_apigen.aliases -%} + {%- set alias_id = alias.target_module + "." + alias.alias_name -%} + {% filter heading( + 9, + role="class", + id=alias_id, + class="doc doc-heading", + hidden=true, + skip_inventory=config.skip_local_inventory, + ) -%}{%- endfilter %} + {%- endfor %} + {% endif %} + {% endblock alias_anchors %} + + {% block source_link scoped %} + {% if config.extra.link_source and class.source_link %} + [source] + {% endif %} + {% endblock source_link %} + + {% if config.show_symbol_type_heading %}{% endif %} + {% if config.heading and root %} + {{ config.heading }} + {% elif config.separate_signature %} + {{ class_name }} + {% elif config.merge_init_into_class and "__init__" in all_members %} + {% with function = all_members["__init__"] %} + {%+ filter highlight(language="python", inline=True) %} + {{ class_name -}} + {%- with obj = function -%} + {%- include "type_parameters.html.jinja" with context -%} + {%- endwith -%} + {%- include "signature.html.jinja" with context -%} + {% endfilter %} + {% endwith %} + {% else %} + {# TODO: Maybe render type parameters here. #} + {{ class_name }} + {% endif %} + {% endblock heading %} + + {% block labels scoped %} + {#- Labels block. + + This block renders the labels for the class. + -#} + {% with labels = class.labels %} + {% include "labels.html.jinja" with context %} + {% endwith %} + {% endblock labels %} + + {% endfilter %} + + {% block signature scoped %} + {#- Signature block. + + This block renders the signature for the class. + Overloads of the `__init__` method are rendered if `merge_init_into_class` is enabled. + The actual `__init__` method signature is only rendered if `separate_signature` is also enabled. + + If the class is generic, but the `__init__` method isn't or `merge_init_into_class` is disabled, + the class signature is rendered if `separate_signature` and `show_signature_type_parameters` are enabled. + + If the `__init__` method or any overloads are generic, they are rendered as methods if + `merge_init_into_class`, `separate_signature` and `show_signature_type_parameters` are enabled. + -#} + {% if config.merge_init_into_class and "__init__" in all_members %} + {% with function = all_members["__init__"] %} + {% if function.overloads and config.show_overloads %} +
+ {% for overload in function.overloads %} + {% filter format_signature(overload, config.line_length, annotations=True, crossrefs=config.signature_crossrefs) %} + {{ class.name }} + {% endfilter %} + {% endfor %} +
+ {% endif %} + {% if config.separate_signature and not (config.show_overloads and function.overloads and config.overloads_only) %} + {% filter format_signature(function, config.line_length, crossrefs=config.signature_crossrefs) %} + {{ class.name }} + {% endfilter %} + {% endif %} + {% endwith %} + {% endif %} + {% endblock signature %} + + {% else %} + {% if config.show_root_toc_entry %} + {% filter heading(heading_level, + role="class", + id=html_id, + toc_label=(' '|safe if config.show_symbol_type_toc else '') + (config.toc_label if config.toc_label and root else class.name), + hidden=True, + skip_inventory=config.skip_local_inventory, + ) %} + {% endfilter %} {% endif %} + {% set heading_level = heading_level - 1 %} {% endif %} - {% endblock aliases %} - {{ super() }} -{% endblock contents %} +
+ {% block contents scoped %} + {#- Contents block. + + This block renders the contents of the class. + It contains other blocks that users can override. + Overriding the contents block allows to rearrange the order of the blocks. + -#} + {% block bases scoped %} + {#- Class bases block. + + This block renders the bases for the class. + -#} + {% if config.show_bases and class.bases %} +

+ Bases: {% for expression in class.bases -%} + + {%- with backlink_type = "subclassed-by" -%} + {%- include "expression.html.jinja" with context -%} + {%- endwith -%} + {% if not loop.last %}, {% endif %} + {% endfor -%} +

+ {% endif %} + {% endblock bases %} + + {% block inheritance_diagram scoped %} + {#- Inheritance diagram block. + + This block renders the inheritance diagram for the class, + using Mermaid syntax and a bit of JavaScript to make the nodes clickable, + linking to the corresponding class documentation. + -#} + {% if config.show_inheritance_diagram and class.bases %} + {% macro edges(class) %} + {% for base in class.resolved_bases %} + {{ base.path }} --> {{ class.path }} + {{ edges(base) }} + {% endfor %} + {% endmacro %} +
+ + {% for base in class.mro() %} + + {% endfor %} +
+

+              flowchart {{ config.inheritance_diagram_direction }}
+              {{ class.path }}[{{ class.name }}]
+              {% for base in class.mro() %}
+              {{ base.path }}[{{ base.name }}]
+              {% endfor %}
+
+              {{ edges(class) | safe }}
+
+              click {{ class.path }} href "" "{{ class.path }}"
+              {% for base in class.mro() %}
+              click {{ base.path }} href "" "{{ base.path }}"
+              {% endfor %}
+            
+ + {% endif %} + {% endblock inheritance_diagram %} + + {% block docstring scoped %} + {#- Docstring block. + + This block renders the docstring for the class. + -#} + {% with docstring_sections = class.docstring.parsed %} + {% include "docstring.html.jinja" with context %} + {% endwith %} + {% if config.merge_init_into_class %} + {# We don't want to merge the inherited `__init__` method docstring into the class docstring #} + {# if such inherited method was not selected through `inherited_members`. #} + {% with check_members = all_members if (config.inherited_members is true or (config.inherited_members is iterable and "__init__" in config.inherited_members)) else class.members %} + {% if "__init__" in check_members and check_members["__init__"].has_docstring %} + {% with function = check_members["__init__"] %} + {% with obj = function, docstring_sections = function.docstring.parsed %} + {% include "docstring.html.jinja" with context %} + {% endwith %} + {% endwith %} + {% endif %} + {% endwith %} + {% endif %} + {% endblock docstring %} + + {% block aliases scoped %} + {% if class.extra.hopsworks_apigen and class.extra.hopsworks_apigen.aliases %} + {%- set public_aliases = class.extra.hopsworks_apigen.aliases | selectattr("is_public") | list -%} + {% if public_aliases and public_aliases[1:] %} +

+ For backwards compatibility + {% set fullpath = public_aliases[0].target_module + "." + public_aliases[0].alias_name %} + {{fullpath}} + is still available as + {% for alias in public_aliases[1:] -%} + {%- set fullpath = alias.target_module + "." + alias.alias_name -%} + {{fullpath}} + {%- if not loop.last %}, {% endif %} + {%- endfor %}. + {% if public_aliases[2:] %} + The use of these aliases is discouraged as they are to be deprecated. + {% else %} + The use of this alias is discouraged as it is to be deprecated. + {% endif %} +

+ {% endif %} + {% endif %} + {% endblock aliases %} + + {% block backlinks scoped %} + {% if class.extra.hopsworks_apigen and class.extra.hopsworks_apigen.aliases %} + + {% endif %} + {% endblock backlinks %} + + {% block summary scoped %} + {#- Summary block. + + This block renders auto-summaries for classes, methods, and attributes. + -#} + {% include "summary.html.jinja" with context %} + {% endblock summary %} + + {% block source scoped %} + {#- Source block. + + This block renders the source code for the class. + -#} + {% if config.show_source %} + {% if config.merge_init_into_class %} + {% if "__init__" in all_members and all_members["__init__"].source %} + {% with init = all_members["__init__"] %} +
+ {{ lang.t("Source code in") }} + {%- if init.relative_filepath.is_absolute() -%} + {{ init.relative_package_filepath }} + {%- else -%} + {{ init.relative_filepath }} + {%- endif -%} + + {{ init.source|highlight(language="python", linestart=init.lineno or 0, linenums=True) }} +
+ {% endwith %} + {% endif %} + {% elif class.source %} +
+ {{ lang.t("Source code in") }} + {%- if class.relative_filepath.is_absolute() -%} + {{ class.relative_package_filepath }} + {%- else -%} + {{ class.relative_filepath }} + {%- endif -%} + + {{ class.source|highlight(language="python", linestart=class.lineno or 0, linenums=True) }} +
+ {% endif %} + {% endif %} + {% endblock source %} + + {% block children scoped %} + {#- Children block. + + This block renders the children (members) of the class. + -#} + {% set root = False %} + {% set heading_level = heading_level + 1 %} + {% include "children.html.jinja" with context %} + {% endblock children %} + {% endblock contents %} +
+ + {% endwith %} +
diff --git a/docs/templates/python/material/function.html.jinja b/docs/templates/python/material/function.html.jinja index 494f3e379f..b2f67aee97 100644 --- a/docs/templates/python/material/function.html.jinja +++ b/docs/templates/python/material/function.html.jinja @@ -1,60 +1,219 @@ -{% extends "_base/function.html.jinja" %} +{#- Template for Python functions. -{% block heading scoped %} - {% block alias_anchors scoped %} - {% if function.extra.hopsworks_apigen and function.extra.hopsworks_apigen.aliases %} - {% for alias in function.extra.hopsworks_apigen.aliases -%} - {%- set alias_id = alias.target_module + "." + alias.alias_name -%} - {% filter heading( - 9, - role="function", - id=alias_id, - class="doc doc-heading", - hidden=true, - skip_inventory=config.skip_local_inventory, - ) -%}{%- endfilter %} - {%- endfor %} +This template renders a Python function or method. + +Context: + function (griffe.Function): The function to render. + root (bool): Whether this is the root object, injected with `:::` in a Markdown page. + heading_level (int): The HTML heading level to use. + config (dict): The configuration options. +-#} + +{% block logs scoped %} + {#- Logging block. + + This block can be used to log debug messages, deprecation messages, warnings, etc. + -#} + {{ log.debug("Rendering " + function.path) }} +{% endblock logs %} + +{% import "language.html.jinja" as lang with context %} +{#- Language module providing the `t` translation method. -#} + +
+ {% with obj = function, html_id = function.path %} + + {% if root %} + {% set show_full_path = config.show_root_full_path %} + {% set root_members = True %} + {% elif root_members %} + {% set show_full_path = config.show_root_members_full_path or config.show_object_full_path %} + {% set root_members = False %} + {% else %} + {% set show_full_path = config.show_object_full_path %} {% endif %} - {% if function.parent and function.parent.extra.hopsworks_apigen and function.parent.extra.hopsworks_apigen.aliases %} - {% for alias in function.parent.extra.hopsworks_apigen.aliases -%} - {%- set alias_id = alias.target_module + "." + alias.alias_name + "." + function.name -%} - {% filter heading( - 9, + + {% set function_name = function.path if show_full_path else function.name %} + {#- Brief or full function name depending on configuration. -#} + {% set symbol_type = "method" if function.parent.is_class else "function" %} + {#- Symbol type: method when parent is a class, function otherwise. -#} + + {% if not root or config.show_root_heading %} + {% filter heading( + heading_level, role="function", - id=alias_id, + id=html_id, class="doc doc-heading", - hidden=true, + toc_label=((' ')|safe if config.show_symbol_type_toc else '') + (config.toc_label if config.toc_label and root else function.name), skip_inventory=config.skip_local_inventory, - ) -%}{%- endfilter %} - {%- endfor %} - {% endif %} - {% endblock alias_anchors %} + ) %} - {% block source_link scoped %} - {% if config.extra.link_source and function.source_link %} - [source] - {% endif %} - {% endblock source_link %} - - {{ super() }} - -{% endblock heading %} - -{% block contents scoped %} - {% block aliases scoped %} - {% if function.extra.hopsworks_apigen and function.extra.hopsworks_apigen.aliases %} - {%- set public_aliases = function.extra.hopsworks_apigen.aliases | selectattr("is_public") | list -%} - {% if public_aliases and public_aliases[1:] %} -

- Aliases: {% for alias in public_aliases[1:] -%} - {%- set fullpath = alias.target_module + "." + alias.alias_name -%} - {{fullpath}} - {%- if not loop.last %}, {% endif %} - {%- endfor %} -

+ {% block heading scoped %} + {#- Heading block. + + This block renders the heading for the function. + -#} + {% block alias_anchors scoped %} + {% if function.extra.hopsworks_apigen and function.extra.hopsworks_apigen.aliases %} + {% for alias in function.extra.hopsworks_apigen.aliases -%} + {%- set alias_id = alias.target_module + "." + alias.alias_name -%} + {% filter heading( + 9, + role="function", + id=alias_id, + class="doc doc-heading", + hidden=true, + skip_inventory=config.skip_local_inventory, + ) -%}{%- endfilter %} + {%- endfor %} + {% endif %} + {% if function.parent and function.parent.extra.hopsworks_apigen and function.parent.extra.hopsworks_apigen.aliases %} + {% for alias in function.parent.extra.hopsworks_apigen.aliases -%} + {%- set alias_id = alias.target_module + "." + alias.alias_name + "." + function.name -%} + {% filter heading( + 9, + role="function", + id=alias_id, + class="doc doc-heading", + hidden=true, + skip_inventory=config.skip_local_inventory, + ) -%}{%- endfilter %} + {%- endfor %} + {% endif %} + {% endblock alias_anchors %} + + {% block source_link scoped %} + {% if config.extra.link_source and function.source_link %} + [source] + {% endif %} + {% endblock source_link %} + + {% if config.show_symbol_type_heading %}{% endif %} + {% if config.heading and root %} + {{ config.heading }} + {% elif config.separate_signature %} + {{ function_name }} + {% else %} + {%+ filter highlight(language="python", inline=True) -%} + {{ function_name }} + {%- include "type_parameters.html.jinja" with context -%} + {%- include "signature.html.jinja" with context -%} + {%- endfilter %} + {% endif %} + {% endblock heading %} + + {% block labels scoped %} + {#- Labels block. + + This block renders the labels for the function. + -#} + {% with labels = function.labels %} + {% include "labels.html.jinja" with context %} + {% endwith %} + {% endblock labels %} + + {% endfilter %} + + {% block signature scoped %} + {#- Signature block. + + This block renders the signature for the function, + as well as its overloaded signatures if any. + -#} + {% if function.overloads and config.show_overloads %} +
+ {% for overload in function.overloads %} + {% filter format_signature(overload, config.line_length, annotations=True, crossrefs=config.signature_crossrefs) %} + {{ overload.name }} + {% endfilter %} + {% endfor %} +
+ {% endif %} + {% if config.separate_signature and not (config.show_overloads and function.overloads and config.overloads_only) %} + {% filter format_signature(function, config.line_length, crossrefs=config.signature_crossrefs) %} + {{ function.name }} + {% endfilter %} + {% endif %} + {% endblock signature %} + + {% else %} + + {% if config.show_root_toc_entry %} + {% filter heading( + heading_level, + role="function", + id=html_id, + toc_label=((' ')|safe if config.show_symbol_type_toc else '') + (config.toc_label if config.toc_label and root else function.name), + hidden=True, + skip_inventory=config.skip_local_inventory, + ) %} + {% endfilter %} {% endif %} + {% set heading_level = heading_level - 1 %} {% endif %} - {% endblock aliases %} - {{ super() }} -{% endblock contents %} +
+ {% block contents scoped %} + {#- Contents block. + + This block renders the contents of the function. + It contains other blocks that users can override. + Overriding the contents block allows to rearrange the order of the blocks. + -#} + {% block aliases scoped %} + {% if function.extra.hopsworks_apigen and function.extra.hopsworks_apigen.aliases %} + {%- set public_aliases = function.extra.hopsworks_apigen.aliases | selectattr("is_public") | list -%} + {% if public_aliases and public_aliases[1:] %} +

+ For backwards compatibility + {% set fullpath = public_aliases[0].target_module + "." + public_aliases[0].alias_name %} + {{fullpath}} + is still available as + {% for alias in public_aliases[1:] -%} + {%- set fullpath = alias.target_module + "." + alias.alias_name -%} + {{fullpath}} + {%- if not loop.last %}, {% endif %} + {%- endfor %}. + {% if public_aliases[2:] %} + The use of these aliases is discouraged as they are to be deprecated. + {% else %} + The use of this alias is discouraged as it is to be deprecated. + {% endif %} +

+ {% endif %} + {% endif %} + {% endblock aliases %} + + {% block docstring scoped %} + {#- Docstring block. + + This block renders the docstring for the function. + -#} + {% with docstring_sections = function.docstring.parsed %} + {% include "docstring.html.jinja" with context %} + {% endwith %} + {% endblock docstring %} + + {% block source scoped %} + {#- Source block. + + This block renders the source code for the function. + -#} + {% if config.show_source and function.source %} +
+ {{ lang.t("Source code in") }} + {%- if function.relative_filepath.is_absolute() -%} + {{ function.relative_package_filepath }} + {%- else -%} + {{ function.relative_filepath }} + {%- endif -%} + + {{ function.source|highlight(language="python", linestart=function.lineno or 0, linenums=True) }} +
+ {% endif %} + {% endblock source %} + {% endblock contents %} +
+ + {% endwith %} +
diff --git a/docs/templates/python/material/module.html.jinja b/docs/templates/python/material/module.html.jinja index a61acfda9b..1fb1cb6950 100644 --- a/docs/templates/python/material/module.html.jinja +++ b/docs/templates/python/material/module.html.jinja @@ -1,12 +1,131 @@ -{% extends "_base/module.html.jinja" %} +{#- Template for Python modules. -{% block heading scoped %} - {% block source_link scoped %} - {% if config.extra.link_source and module.source_link %} - [source] +This template renders a Python module. + +Context: + module (griffe.Module): The module to render. + root (bool): Whether this is the root object, injected with `:::` in a Markdown page. + heading_level (int): The HTML heading level to use. + config (dict): The configuration options. +-#} + +{% block logs scoped %} + {#- Logging block. + + This block can be used to log debug messages, deprecation messages, warnings, etc. + -#} + {{ log.debug("Rendering " + module.path) }} +{% endblock logs %} + +
+ {% with obj = module, html_id = module.path %} + + {% if root %} + {% set show_full_path = config.show_root_full_path %} + {% set root_members = True %} + {% elif root_members %} + {% set show_full_path = config.show_root_members_full_path or config.show_object_full_path %} + {% set root_members = False %} + {% else %} + {% set show_full_path = config.show_object_full_path %} {% endif %} - {% endblock source_link %} - {{ super() }} + {% set module_name = module.path if show_full_path else module.name %} + + {% if not root or config.show_root_heading %} + {% filter heading( + heading_level, + role="module", + id=html_id, + class="doc doc-heading", + toc_label=(' '|safe if config.show_symbol_type_toc else '') + (config.toc_label if config.toc_label and root else module.name), + skip_inventory=config.skip_local_inventory, + ) %} + + {% block heading scoped %} + {#- Heading block. + + This block renders the heading for the module. + -#} + {% block source_link scoped %} + {% if config.extra.link_source and module.source_link %} + [source] + {% endif %} + {% endblock source_link %} + + {% if config.show_symbol_type_heading %}{% endif %} + {% if config.heading and root %} + {{ config.heading }} + {% elif config.separate_signature %} + {{ module_name }} + {% else %} + {{ module_name }} + {% endif %} + {% endblock heading %} + + {% block labels scoped %} + {#- Labels block. + + This block renders the labels for the module. + -#} + {% with labels = module.labels %} + {% include "labels.html.jinja" with context %} + {% endwith %} + {% endblock labels %} + + {% endfilter %} + + {% else %} + {% if config.show_root_toc_entry %} + {% filter heading(heading_level, + role="module", + id=html_id, + toc_label=(' '|safe if config.show_symbol_type_toc else '') + (config.toc_label if config.toc_label and root else module.name), + hidden=True, + skip_inventory=config.skip_local_inventory, + ) %} + {% endfilter %} + {% endif %} + {% set heading_level = heading_level - 1 %} + {% endif %} + +
+ {% block contents scoped %} + {#- Contents block. + + This block renders the contents of the module. + It contains other blocks that users can override. + Overriding the contents block allows to rearrange the order of the blocks. + -#} + {% block docstring scoped %} + {#- Docstring block. + + This block renders the docstring for the module. + -#} + {% with docstring_sections = module.docstring.parsed %} + {% include "docstring.html.jinja" with context %} + {% endwith %} + {% endblock docstring %} + + {% block summary scoped %} + {#- Summary block. + + This block renders auto-summaries for classes, methods, and attributes. + -#} + {% include "summary.html.jinja" with context %} + {% endblock summary %} + + {% block children scoped %} + {#- Children block. + + This block renders the children (members) of the module. + -#} + {% set root = False %} + {% set heading_level = heading_level + 1 %} + {% include "children.html.jinja" with context %} + {% endblock children %} + {% endblock contents %} +
-{% endblock heading %} + {% endwith %} +
diff --git a/mkdocs.yml b/mkdocs.yml index 0758f36b67..ac8f38eec9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -327,6 +327,7 @@ extra_javascript: plugins: - search + - autorefs - minify: minify_html: true minify_css: true @@ -358,6 +359,7 @@ plugins: docstring_section_style: spacy annotations_path: source filters: public + backlinks: flat extra: link_source: true extensions: diff --git a/requirements-docs.txt b/requirements-docs.txt index ad8d20e1e0..40215a7826 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -4,8 +4,9 @@ mike==2.1.3 markdown==3.9 pymdown-extensions==10.17.2 mkdocs-minify-plugin>=0.2.0 -hopsworks-apigen@git+https://github.com/aversey/hopsworks-aliases.git -mkdocstrings[python]==1.0.0 -mkdocstrings-python==2.0.1 +hopsworks-apigen@git+https://github.com/logicalclocks/hopsworks-apigen.git +mkdocstrings[python]==1.0.3 +mkdocstrings-python==2.0.2 +mkdocs-autorefs==1.4.4 ruff==0.15.0 linkchecker From e8814d7d3d4df3aef27a9595a821c0acecbd4a63 Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Tue, 17 Feb 2026 16:28:12 +0100 Subject: [PATCH 10/15] Use PyPI version of hopsworks-apigen --- requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-docs.txt b/requirements-docs.txt index 40215a7826..3e50579236 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -4,7 +4,7 @@ mike==2.1.3 markdown==3.9 pymdown-extensions==10.17.2 mkdocs-minify-plugin>=0.2.0 -hopsworks-apigen@git+https://github.com/logicalclocks/hopsworks-apigen.git +hopsworks-apigen==1.0.0 mkdocstrings[python]==1.0.3 mkdocstrings-python==2.0.2 mkdocs-autorefs==1.4.4 From 4ebf37603f869aae4d5558880f9ae3a83858857b Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Wed, 18 Feb 2026 17:43:25 +0100 Subject: [PATCH 11/15] Change back to the official API repo --- .github/workflows/mkdocs-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mkdocs-test.yml b/.github/workflows/mkdocs-test.yml index 93a8527f61..fa2c942f10 100644 --- a/.github/workflows/mkdocs-test.yml +++ b/.github/workflows/mkdocs-test.yml @@ -15,7 +15,7 @@ jobs: - name: Checkout the API repo uses: actions/checkout@v4 with: - repository: aversey/hopsworks-api + repository: logicalclocks/hopsworks-api ref: ${{ github.base_ref }} path: hopsworks-api From d6c999ff9d12ed68e79503600940ff92891cf574 Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Wed, 18 Feb 2026 17:47:15 +0100 Subject: [PATCH 12/15] In release workflow too --- .github/workflows/mkdocs-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mkdocs-release.yml b/.github/workflows/mkdocs-release.yml index 4a751fc7d7..63ffc0f23f 100644 --- a/.github/workflows/mkdocs-release.yml +++ b/.github/workflows/mkdocs-release.yml @@ -59,7 +59,7 @@ jobs: - name: Checkout the API repo uses: actions/checkout@v4 with: - repository: aversey/hopsworks-api + repository: logicalclocks/hopsworks-api ref: ${{ env.BRANCH }} path: hopsworks-api From dbd6dcfbefc998b03916036532d42a8af9a8e9a2 Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Fri, 20 Feb 2026 15:21:30 +0100 Subject: [PATCH 13/15] Unhide logs of mkdocs --- .github/workflows/mkdocs-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mkdocs-test.yml b/.github/workflows/mkdocs-test.yml index fa2c942f10..34f51f1ad4 100644 --- a/.github/workflows/mkdocs-test.yml +++ b/.github/workflows/mkdocs-test.yml @@ -64,7 +64,7 @@ jobs: - name: Check for broken links run: | # run the server - mkdocs serve > /dev/null 2>&1 & + mkdocs serve 2>&1 & SERVER_PID=$! echo "mk server in PID $SERVER_PID" # Give enough time for deployment (2min max) From c4695897728f3cbc93595e2ba966301817002eaf Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Fri, 20 Feb 2026 15:25:13 +0100 Subject: [PATCH 14/15] Quiet mkdocs --- .github/workflows/mkdocs-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mkdocs-test.yml b/.github/workflows/mkdocs-test.yml index 34f51f1ad4..4ad6b53a79 100644 --- a/.github/workflows/mkdocs-test.yml +++ b/.github/workflows/mkdocs-test.yml @@ -64,7 +64,7 @@ jobs: - name: Check for broken links run: | # run the server - mkdocs serve 2>&1 & + mkdocs serve -q & SERVER_PID=$! echo "mk server in PID $SERVER_PID" # Give enough time for deployment (2min max) From 1c333342715010e2314f300c91c35efbd54579fe Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Fri, 20 Feb 2026 15:51:03 +0100 Subject: [PATCH 15/15] Remove docs group --- .github/workflows/mkdocs-release.yml | 2 +- .github/workflows/mkdocs-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mkdocs-release.yml b/.github/workflows/mkdocs-release.yml index 63ffc0f23f..593420a801 100644 --- a/.github/workflows/mkdocs-release.yml +++ b/.github/workflows/mkdocs-release.yml @@ -92,7 +92,7 @@ jobs: working-directory: hopsworks-api/python - name: Install Python API dependencies - run: uv sync --extra dev --group docs --project hopsworks-api/python + run: uv sync --extra dev --project hopsworks-api/python - name: Install Python dependencies run: uv pip install -r requirements-docs.txt diff --git a/.github/workflows/mkdocs-test.yml b/.github/workflows/mkdocs-test.yml index 4ad6b53a79..c86687a2d3 100644 --- a/.github/workflows/mkdocs-test.yml +++ b/.github/workflows/mkdocs-test.yml @@ -53,7 +53,7 @@ jobs: working-directory: hopsworks-api/python - name: Install Python API dependencies - run: uv sync --extra dev --group docs --project hopsworks-api/python + run: uv sync --extra dev --project hopsworks-api/python - name: Install Python dependencies run: uv pip install -r requirements-docs.txt