From e7cf5ffba5d9b11ff7d2fafe9a3d56c94bdfdf16 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Fri, 21 Feb 2025 12:08:55 -0800 Subject: [PATCH 01/21] Add pre-commit code quality tools --- .pre-commit-config.yaml | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5c39aa38a..a998b6343 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,31 @@ repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: "v5.0.0" hooks: - - id: trailing-whitespace + - id: check-builtin-literals + - id: check-case-conflict + - id: check-toml + - id: check-yaml + - id: debug-statements + - id: end-of-file-fixer + - id: trailing-whitespace + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.9.7 + hooks: + - id: ruff-format + exclude: examples + - id: ruff + args: ["--fix", "--show-fixes"] + + - repo: https://github.com/rbubley/mirrors-prettier + rev: "v3.4.2" + hooks: + - id: prettier + types_or: [yaml, markdown, html, css, scss, javascript, json] + + - repo: https://github.com/abravalheri/validate-pyproject + rev: "v0.23" + hooks: + - id: validate-pyproject + additional_dependencies: ["validate-pyproject-schema-store[all]"] From c54b2e9de85f3bbfd2a8d51e67e12afe49eca7ce Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Fri, 21 Feb 2025 13:27:41 -0800 Subject: [PATCH 02/21] Annotate scripts for debug --- docs/_scripts/prep_docs.py | 36 ++++++-- docs/_scripts/update_event_docs.py | 113 ++++++++++------------- docs/_scripts/update_preference_docs.py | 11 ++- docs/_scripts/update_ui_sections_docs.py | 81 ++++++++-------- 4 files changed, 125 insertions(+), 116 deletions(-) diff --git a/docs/_scripts/prep_docs.py b/docs/_scripts/prep_docs.py index 1098567d1..ce110388c 100644 --- a/docs/_scripts/prep_docs.py +++ b/docs/_scripts/prep_docs.py @@ -1,38 +1,58 @@ """ALL pre-rendering and pre-preparation of docs should occur in this file. +This script is called **before** Sphinx builds the documentation. + Note: make no assumptions about the working directory from which this script will be called. """ + import sys -from pathlib import Path from importlib.metadata import version +from pathlib import Path from packaging.version import parse +# Set up paths to docs and npe2 docs source DOCS = Path(__file__).parent.parent.absolute() -NPE = DOCS.parent.absolute() / 'npe2' +print(DOCS) +NPE = DOCS.parent.absolute() / "npe2" +print(NPE) + def prep_npe2(): - # some plugin docs live in npe2 for testing purposes + """Preps the npe2 plugin engine prior to Sphinx docs build. + + Some plugin-related docs live in the npe2 repo to simplify + plugin testing. + """ + print("Entered prep_npe2") + # Checks if the path to npe2 repo exist. If so, bail. if NPE.exists(): + print("npe2 is already installed. moving on") return from subprocess import check_call npe2_version = version("npe2") - + print(f"npe2 version: {npe2_version}") check_call(f"rm -rf {NPE}".split()) + print("removing NPE directory succeeded") check_call(f"git clone https://github.com/napari/npe2 {NPE}".split()) + if not parse(npe2_version).is_devrelease: check_call(f"git checkout tags/v{npe2_version}".split(), cwd=NPE) - check_call([sys.executable, f"{NPE}/_docs/render.py", DOCS / 'plugins']) + + check_call([sys.executable, f"{NPE}/_docs/render.py", DOCS / "plugins"]) check_call(f"rm -rf {NPE}".split()) def main(): prep_npe2() - __import__('update_preference_docs').main() - __import__('update_event_docs').main() - __import__('update_ui_sections_docs').main() + __import__("update_preference_docs").main() + print("update_preference_docs succeeded") + __import__("update_event_docs").main() + print("update_event_docs succeeded") + __import__("update_ui_sections_docs").main() + print("update_ui_sections_docs succeeded") if __name__ == "__main__": diff --git a/docs/_scripts/update_event_docs.py b/docs/_scripts/update_event_docs.py index 572c5469c..71254fd78 100644 --- a/docs/_scripts/update_event_docs.py +++ b/docs/_scripts/update_event_docs.py @@ -15,6 +15,7 @@ from napari.components.viewer_model import ViewerModel from napari.utils.events import EventedModel +print("imports in update_event_docs succeeded") DOCS = Path(__file__).parent.parent @@ -28,47 +29,47 @@ class Ev: def access_at(self): """Where this event can be accessed (in code)""" if issubclass(self.model, layers.Layer): - return f'layer.events.{self.name}' + return f"layer.events.{self.name}" if issubclass(self.model, LayerList): - if self.name.startswith('selection.'): - return f'layers.selection.events.{self.name[10:]}' - return f'layers.events.{self.name}' + if self.name.startswith("selection."): + return f"layers.selection.events.{self.name[10:]}" + return f"layers.events.{self.name}" if issubclass(self.model, ViewerModel): - return f'viewer.events.{self.name}' + return f"viewer.events.{self.name}" for name, field_ in napari.Viewer.__fields__.items(): if field_.type_ is self.model: - return f'viewer.{name}.events.{self.name}' - return '' + return f"viewer.{name}.events.{self.name}" + return "" def type_name(self): - if cls_name := getattr(self.type_, '__name__', None): + if cls_name := getattr(self.type_, "__name__", None): return cls_name - name = str(self.type_) if self.type_ else '' + name = str(self.type_) if self.type_ else "" return name.replace("typing.", "") def ev_model_row(self) -> List[str]: return [ - f'`{self.model.__name__}`', - f'`{self.name}`', - f'`{self.access_at()}`', - self.description or '', - f'`{self.type_name()}`', + f"`{self.model.__name__}`", + f"`{self.name}`", + f"`{self.access_at()}`", + self.description or "", + f"`{self.type_name()}`", ] def layer_row(self) -> List[str]: return [ - f'`{self.model.__name__}`', - f'`{self.name}`', - f'`{self.access_at()}`', - self.description or '', - '', + f"`{self.model.__name__}`", + f"`{self.name}`", + f"`{self.access_at()}`", + self.description or "", + "", ] def walk_modules( - module: ModuleType, pkg='napari', _walked=None + module: ModuleType, pkg="napari", _walked=None ) -> Iterator[ModuleType]: """walk all modules in pkg, starting with `module`.""" if not _walked: @@ -94,10 +95,8 @@ def iter_classes(module: ModuleType) -> Iterator[Type]: def class_doc_attrs(kls: Type) -> Dict[str, Parameter]: - docs = {p.name: " ".join(p.desc) for p in ClassDoc(kls).get('Attributes')} - docs.update( - {p.name: " ".join(p.desc) for p in ClassDoc(kls).get('Parameters')} - ) + docs = {p.name: " ".join(p.desc) for p in ClassDoc(kls).get("Attributes")} + docs.update({p.name: " ".join(p.desc) for p in ClassDoc(kls).get("Parameters")}) return docs @@ -110,11 +109,7 @@ def iter_evented_model_events(module: ModuleType = napari) -> Iterator[Ev]: for name, field_ in kls.__fields__.items(): finfo = field_.field_info if finfo.allow_mutation: - descr = ( - f"{finfo.title.lower()}" - if finfo.title - else docs.get(name) - ) + descr = f"{finfo.title.lower()}" if finfo.title else docs.get(name) yield Ev(name, kls, descr, field_.type_) @@ -130,13 +125,13 @@ def iter_evented_container_events( for name, emitter in kls_instance.events._emitters.items(): descr = docs.get(name) yield Ev(name, kls, descr, type_=None) - if hasattr(kls_instance, 'selection'): + if hasattr(kls_instance, "selection"): selection = kls_instance.selection for name, emitter in selection.events._emitters.items(): - if name.startswith('_'): + if name.startswith("_"): # skip private emitters continue - name = 'selection.' + name + name = "selection." + name descr = docs.get(name) yield Ev(name, kls, descr, type_=None) @@ -147,7 +142,7 @@ def __init__(self) -> None: self._emitters: List[str] = [] def visit_Call(self, node: ast.Call): - if getattr(node.func, 'id', None) == 'EmitterGroup': + if getattr(node.func, "id", None) == "EmitterGroup": self._emitters.extend([name.arg for name in node.keywords]) # type: ignore @@ -195,9 +190,9 @@ def iter_layer_events() -> Iterator[Ev]: def merge_image_and_label_rows(rows: List[List[str]]): """Merge events common to _ImageBase or IntensityVisualizationMixin.""" # find events that are common across both Image, Labels and Surface layers. - image_events = {r[1] for r in rows if r[0] == '`Image`'} - labels_events = {r[1] for r in rows if r[0] == '`Labels`'} - surface_events = {r[1] for r in rows if r[0] == '`Surface`'} + image_events = {r[1] for r in rows if r[0] == "`Image`"} + labels_events = {r[1] for r in rows if r[0] == "`Labels`"} + surface_events = {r[1] for r in rows if r[0] == "`Surface`"} common_events = image_events & labels_events & surface_events # common only to Image and Labels imagebase_events = (image_events & labels_events) - common_events @@ -206,24 +201,24 @@ def merge_image_and_label_rows(rows: List[List[str]]): rows = [ r for r in rows - if not (r[0] in ['`Labels`', '`Surface`'] and r[1] in common_events) + if not (r[0] in ["`Labels`", "`Surface`"] and r[1] in common_events) ] rows = [ r for r in rows - if not (r[0] in ['`Labels`', '`Surface`'] and r[1] in imagebase_events) + if not (r[0] in ["`Labels`", "`Surface`"] and r[1] in imagebase_events) ] # modify the class name of the Image entries to mention Labels, Surface rows = [ - ['`Image`, `Labels`'] + r[1:] - if r[0] == '`Image`' and r[1] in imagebase_events + ["`Image`, `Labels`"] + r[1:] + if r[0] == "`Image`" and r[1] in imagebase_events else r for r in rows ] rows = [ - ['`Image`, `Labels`, `Surface`'] + r[1:] - if r[0] == '`Image`' and r[1] in common_events + ["`Image`, `Labels`, `Surface`"] + r[1:] + if r[0] == "`Image`" and r[1] in common_events else r for r in rows ] @@ -232,45 +227,39 @@ def merge_image_and_label_rows(rows: List[List[str]]): def main(): HEADER = [ - 'Event', - 'Description', - 'Event.value type', + "Event", + "Description", + "Event.value type", ] # Do viewer events rows = [ - ev.ev_model_row()[2:] - for ev in iter_evented_model_events() - if ev.access_at() + ev.ev_model_row()[2:] for ev in iter_evented_model_events() if ev.access_at() ] table1 = table_repr(rows, padding=2, header=HEADER, divide_rows=False) - (DOCS / 'guides' / '_viewer_events.md').write_text(table1) + (DOCS / "guides" / "_viewer_events.md").write_text(table1) # Do LayerList events rows = [ ev.layer_row()[2:] - for ev in iter_evented_container_events( - napari, container_class=LayerList - ) + for ev in iter_evented_container_events(napari, container_class=LayerList) if ev.access_at() ] table2 = table_repr(rows, padding=2, header=HEADER, divide_rows=False) - (DOCS / 'guides' / '_layerlist_events.md').write_text(table2) + (DOCS / "guides" / "_layerlist_events.md").write_text(table2) # Do layer events HEADER = [ - 'Class', - 'Event', - 'Description', - 'Event.value type', - ] - rows = [ - [ev.layer_row()[0]] + ev.layer_row()[2:] for ev in iter_layer_events() + "Class", + "Event", + "Description", + "Event.value type", ] + rows = [[ev.layer_row()[0]] + ev.layer_row()[2:] for ev in iter_layer_events()] rows = merge_image_and_label_rows(rows) table3 = table_repr(rows, padding=2, header=HEADER, divide_rows=False) - (DOCS / 'guides' / '_layer_events.md').write_text(table3) + (DOCS / "guides" / "_layer_events.md").write_text(table3) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/docs/_scripts/update_preference_docs.py b/docs/_scripts/update_preference_docs.py index ef60c7fef..5c621b58f 100644 --- a/docs/_scripts/update_preference_docs.py +++ b/docs/_scripts/update_preference_docs.py @@ -1,13 +1,13 @@ from pathlib import Path from jinja2 import Template -from napari._pydantic_compat import ModelMetaclass from qtpy.QtCore import QTimer from qtpy.QtWidgets import QMessageBox from napari._qt.dialogs.preferences_dialog import PreferencesDialog from napari._qt.qt_event_loop import get_qapp from napari._qt.qt_resources import get_stylesheet +from napari._pydantic_compat import ModelMetaclass from napari.settings import NapariSettings DOCS = REPO_ROOT_PATH = Path(__file__).resolve().parent.parent @@ -134,7 +134,6 @@ def create_preferences_docs(): sections = {} for name, field in NapariSettings.__fields__.items(): - if not isinstance(field.type_, ModelMetaclass): continue @@ -142,7 +141,7 @@ def create_preferences_docs(): title = field.field_info.title or name sections[title.lower()] = { "title": title, - "description": field.field_info.description or '', + "description": field.field_info.description or "", "fields": [ { "field": n, @@ -150,10 +149,10 @@ def create_preferences_docs(): "description": f.field_info.description, "default": repr(f.get_default()), "ui": n not in excluded, - "type": repr(f._type_display()).replace('.typing', ''), + "type": repr(f._type_display()).replace(".typing", ""), } for n, f in sorted(field.type_.__fields__.items()) - if n not in ('schema_version') + if n not in ("schema_version") ], } @@ -171,7 +170,9 @@ def create_preferences_docs(): def main(): + print("start generate image") generate_images() + print("generate preferences docs") create_preferences_docs() diff --git a/docs/_scripts/update_ui_sections_docs.py b/docs/_scripts/update_ui_sections_docs.py index 9fd8f6bb9..0ac5a3206 100644 --- a/docs/_scripts/update_ui_sections_docs.py +++ b/docs/_scripts/update_ui_sections_docs.py @@ -2,20 +2,21 @@ import json from pathlib import Path +# ---- Third-party imports +import seedir as sd +from pydeps import cli, colors, dot, py2depgraph +from pydeps.pydeps import depgraph_to_dotsrc +from pydeps.target import Target + # ---- Napari imports +from napari._qt import dialogs +from napari._qt import qt_viewer from napari._qt.containers import qt_layer_list from napari._qt.layer_controls import qt_layer_controls_container -from napari._qt.widgets import qt_viewer_status_bar from napari._qt._qapp_model import qactions -from napari._qt import qt_viewer -from napari._qt import dialogs +from napari._qt.widgets import qt_viewer_status_bar from napari_console import qt_console -# ---- Third-party imports -from pydeps import cli, colors, dot, py2depgraph -from pydeps.pydeps import depgraph_to_dotsrc -from pydeps.target import Target -import seedir as sd # ---- General constants # Docs paths @@ -32,6 +33,8 @@ DIALOGS_MODULE_PATH = Path(dialogs.__file__).parent CONSOLE_MODULE_PATH = Path(qt_console.__file__).parent +print("set paths in update ui sections") + # ---- Utility functions def generate_dependencies_graph(options): @@ -206,13 +209,8 @@ def generate_mermaid_diagram( if "imports" in dependency: dep_imports = dependency["imports"] for dep_import_name in dep_imports: - if ( - dep_import_name != dep_name - and dep_import_name not in dep_name - ): - mermaid_diagram_content += ( - f"\t{dep_name} --> {dep_import_name}\n" - ) + if dep_import_name != dep_name and dep_import_name not in dep_name: + mermaid_diagram_content += f"\t{dep_name} --> {dep_import_name}\n" if graph_urls_prefix and dependency["path"]: module_path = Path(dependency["path"]) # Check if module is outside napari, like @@ -222,9 +220,7 @@ def generate_mermaid_diagram( NAPARI_ROOT_DIRECTORY_PATH ).as_posix() module_url = f"{graph_urls_prefix}{module_relative_path}" - mermaid_diagram_content += ( - f'\tclick {dep_name} "{module_url}" _blank\n' - ) + mermaid_diagram_content += f'\tclick {dep_name} "{module_url}" _blank\n' dep_name_parent = ".".join(dep_name.split(".")[:-1]) if dep_name_parent not in subgraphs: subgraphs[dep_name_parent] = [dep_name] @@ -234,18 +230,14 @@ def generate_mermaid_diagram( external_nodes.append(dep_name) for subgraph_key, subgraph_value in subgraphs.items(): - mermaid_diagram_content += ( - f"\tsubgraph module.{subgraph_key}[{subgraph_key}]\n" - ) + mermaid_diagram_content += f"\tsubgraph module.{subgraph_key}[{subgraph_key}]\n" for dep_subgraph_name in subgraph_value: mermaid_diagram_content += f"\t\t {dep_subgraph_name}\n" mermaid_diagram_content += "\tend\n" mermaid_diagram_content += f"\tclass module.{subgraph_key} subgraphs\n" if external_nodes: - mermaid_diagram_content += ( - "\tsubgraph module.external[external]\n" - ) + mermaid_diagram_content += "\tsubgraph module.external[external]\n" for external_node in external_nodes: mermaid_diagram_content += f"\t\t {external_node}\n" mermaid_diagram_content += "\tend\n" @@ -256,17 +248,11 @@ def generate_mermaid_diagram( "\tclassDef subgraphs fill:white,strock:black,color:black;" ) if graph_node_default_style: - mermaid_diagram_content += ( - f"\tclassDef default {graph_node_default_style}\n" - ) + mermaid_diagram_content += f"\tclassDef default {graph_node_default_style}\n" if graph_link_default_style: - mermaid_diagram_content += ( - f"\tlinkStyle default {graph_link_default_style}\n" - ) + mermaid_diagram_content += f"\tlinkStyle default {graph_link_default_style}\n" if graph_node_external_style: - mermaid_diagram_content += ( - f"\tclassDef external {graph_node_external_style}\n" - ) + mermaid_diagram_content += f"\tclassDef external {graph_node_external_style}\n" for external_dep in external_nodes: mermaid_diagram_content += f"\tclass {external_dep} external\n" @@ -310,7 +296,9 @@ def generate_docs_ui_section_page( page_content = f"## {section_name}\n" page_content += "### Dependencies diagram (related `napari` modules)\n" page_content += mermaid_diagram - page_content += "### Source code directory layout (related to modules inside `napari`)\n" + page_content += ( + "### Source code directory layout (related to modules inside `napari`)\n" + ) page_content += directory_layout if output_file: output_file.parent.mkdir(exist_ok=True, parents=True) @@ -388,7 +376,10 @@ def generate_docs_ui_section( # ---- Main and UI sections parameters def main(): - # General 'settings' + print("ui sections created") + ui_sections = [] + + # --- mermaid settings mermaid_graph_base_settings = { "graph_orientation": "LR", "graph_node_default_style": "fill:#00c3ff,color:black;", @@ -396,9 +387,8 @@ def main(): "graph_link_default_style": "stroke:#00c3ff", "graph_urls_prefix": "https://github.com/napari/napari/tree/main/napari/", } - ui_sections = [] - # ---- Layer list section parameters + # --- Layer list section parameters layer_list_section_name = "Layers list" layer_list_output_page = UI_SECTIONS_DOCS_ROOT_PATH / "layers_list_ui.md" layer_list_pydeps_args = [ @@ -433,6 +423,8 @@ def main(): "--show-deps", "--no-output", ] + + print("adding layer list to ui section") ui_sections.append( ( layer_list_section_name, @@ -443,10 +435,9 @@ def main(): ) # ---- Layer controls section parameters + print("start layer controls") layer_controls_section_name = "Layers controls" - layer_controls_output_page = ( - UI_SECTIONS_DOCS_ROOT_PATH / "layers_controls_ui.md" - ) + layer_controls_output_page = UI_SECTIONS_DOCS_ROOT_PATH / "layers_controls_ui.md" layer_controls_pydeps_args = [ f"{LAYER_CONTROLS_MODULE_PATH}", "--exclude", @@ -475,6 +466,8 @@ def main(): "--show-deps", "--no-output", ] + + print("adding layer controls to ui section") ui_sections.append( ( layer_controls_section_name, @@ -514,6 +507,7 @@ def main(): "--show-deps", "--no-output", ] + print("adding application status bar to ui section") ui_sections.append( ( application_status_bar_section_name, @@ -565,6 +559,7 @@ def main(): "--show-deps", "--no-output", ] + print("adding application menus to ui section") ui_sections.append( ( application_menus_section_name, @@ -606,6 +601,7 @@ def main(): "--show-deps", "--no-output", ] + print("adding viewer to ui section") ui_sections.append( ( viewer_section_name, @@ -660,6 +656,7 @@ def main(): "--show-deps", "--no-output", ] + print("adding dialogs to ui section") ui_sections.append( ( dialogs_section_name, @@ -687,6 +684,7 @@ def main(): "--show-deps", "--no-output", ] + print("adding console to ui section") ui_sections.append( ( console_section_name, @@ -696,6 +694,8 @@ def main(): ) ) + print("getting ready to iterate over sections") + print(f"ui sections {ui_sections}") for ( section_name, output_page, @@ -711,5 +711,4 @@ def main(): if __name__ == "__main__": - # ---- Call main main() From 42340e05c2f2661abc34944aac310fb29f7d7d47 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Fri, 21 Feb 2025 17:34:14 -0800 Subject: [PATCH 03/21] Add templates and use pydata sphinx theme --- Makefile | 2 +- docs/_templates/napari-copyright.html | 21 ++ docs/_templates/napari-footer-links.html | 70 +++++++ docs/_templates/page-toc.html | 4 + .../partials/github-light-blue.html | 13 ++ docs/_templates/partials/github.html | 14 ++ .../partials/image-sc-light-blue.html | 39 ++++ docs/_templates/partials/image-sc.html | 40 ++++ .../partials/mastodon-light-blue.html | 13 ++ docs/_templates/partials/mastodon.html | 14 ++ docs/_templates/partials/menu.html | 11 ++ .../partials/napari-hub-light-blue.html | 96 +++++++++ docs/_templates/partials/napari-hub.html | 90 +++++++++ docs/_templates/partials/napari.html | 67 +++++++ .../_templates/partials/zulip-light-blue.html | 20 ++ docs/_templates/partials/zulip.html | 21 ++ docs/conf.py | 183 ++++++++++-------- 17 files changed, 632 insertions(+), 86 deletions(-) create mode 100644 docs/_templates/napari-copyright.html create mode 100644 docs/_templates/napari-footer-links.html create mode 100644 docs/_templates/page-toc.html create mode 100644 docs/_templates/partials/github-light-blue.html create mode 100644 docs/_templates/partials/github.html create mode 100644 docs/_templates/partials/image-sc-light-blue.html create mode 100644 docs/_templates/partials/image-sc.html create mode 100644 docs/_templates/partials/mastodon-light-blue.html create mode 100644 docs/_templates/partials/mastodon.html create mode 100644 docs/_templates/partials/menu.html create mode 100644 docs/_templates/partials/napari-hub-light-blue.html create mode 100644 docs/_templates/partials/napari-hub.html create mode 100644 docs/_templates/partials/napari.html create mode 100644 docs/_templates/partials/zulip-light-blue.html create mode 100644 docs/_templates/partials/zulip.html diff --git a/Makefile b/Makefile index dba1164f0..8cf13b9e9 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: docs clean +make.PHONY: docs clean SPHINXOPTS = diff --git a/docs/_templates/napari-copyright.html b/docs/_templates/napari-copyright.html new file mode 100644 index 000000000..a6f1538b1 --- /dev/null +++ b/docs/_templates/napari-copyright.html @@ -0,0 +1,21 @@ + diff --git a/docs/_templates/napari-footer-links.html b/docs/_templates/napari-footer-links.html new file mode 100644 index 000000000..96dae323b --- /dev/null +++ b/docs/_templates/napari-footer-links.html @@ -0,0 +1,70 @@ + + {% include "partials/napari.html" %} + napari + + + + {% include "partials/napari-hub.html" %} {% include + "partials/napari-hub-light-blue.html" %} + Plugins + + + + {% include "partials/github.html" %} {% include + "partials/github-light-blue.html" %} + Code + + + + {% include "partials/mastodon.html" %} {% include + "partials/mastodon-light-blue.html" %} + Mastodon + + + + {% include "partials/image-sc.html" %} {% include + "partials/image-sc-light-blue.html" %} + Forum + + + + {% include "partials/zulip.html" %} {% include + "partials/zulip-light-blue.html" %} + Chat + diff --git a/docs/_templates/page-toc.html b/docs/_templates/page-toc.html new file mode 100644 index 000000000..dd6639ab1 --- /dev/null +++ b/docs/_templates/page-toc.html @@ -0,0 +1,4 @@ +{% set page_toc = generate_toc_html() %} {%- if page_toc | length >= 1 %} +
{{ _("On this page") }}
+ +{%- endif %} diff --git a/docs/_templates/partials/github-light-blue.html b/docs/_templates/partials/github-light-blue.html new file mode 100644 index 000000000..2735a7dc3 --- /dev/null +++ b/docs/_templates/partials/github-light-blue.html @@ -0,0 +1,13 @@ + + + diff --git a/docs/_templates/partials/github.html b/docs/_templates/partials/github.html new file mode 100644 index 000000000..6898a5df4 --- /dev/null +++ b/docs/_templates/partials/github.html @@ -0,0 +1,14 @@ + + Visit GitHub repository + + diff --git a/docs/_templates/partials/image-sc-light-blue.html b/docs/_templates/partials/image-sc-light-blue.html new file mode 100644 index 000000000..fc7c82f95 --- /dev/null +++ b/docs/_templates/partials/image-sc-light-blue.html @@ -0,0 +1,39 @@ + + + + + + + + diff --git a/docs/_templates/partials/image-sc.html b/docs/_templates/partials/image-sc.html new file mode 100644 index 000000000..449a2f383 --- /dev/null +++ b/docs/_templates/partials/image-sc.html @@ -0,0 +1,40 @@ + + Visit image.sc forum + + + + + + + diff --git a/docs/_templates/partials/mastodon-light-blue.html b/docs/_templates/partials/mastodon-light-blue.html new file mode 100644 index 000000000..e5e7a32e6 --- /dev/null +++ b/docs/_templates/partials/mastodon-light-blue.html @@ -0,0 +1,13 @@ + + + diff --git a/docs/_templates/partials/mastodon.html b/docs/_templates/partials/mastodon.html new file mode 100644 index 000000000..563231f19 --- /dev/null +++ b/docs/_templates/partials/mastodon.html @@ -0,0 +1,14 @@ + + Visit Mastodon page + + diff --git a/docs/_templates/partials/menu.html b/docs/_templates/partials/menu.html new file mode 100644 index 000000000..63e56be20 --- /dev/null +++ b/docs/_templates/partials/menu.html @@ -0,0 +1,11 @@ + + + + + diff --git a/docs/_templates/partials/napari-hub-light-blue.html b/docs/_templates/partials/napari-hub-light-blue.html new file mode 100644 index 000000000..67d49111c --- /dev/null +++ b/docs/_templates/partials/napari-hub-light-blue.html @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_templates/partials/napari-hub.html b/docs/_templates/partials/napari-hub.html new file mode 100644 index 000000000..18e063444 --- /dev/null +++ b/docs/_templates/partials/napari-hub.html @@ -0,0 +1,90 @@ + + Visit napari hub + + + + + + + + + + + + + + diff --git a/docs/_templates/partials/napari.html b/docs/_templates/partials/napari.html new file mode 100644 index 000000000..d581265a7 --- /dev/null +++ b/docs/_templates/partials/napari.html @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_templates/partials/zulip-light-blue.html b/docs/_templates/partials/zulip-light-blue.html new file mode 100644 index 000000000..e91e7051c --- /dev/null +++ b/docs/_templates/partials/zulip-light-blue.html @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/docs/_templates/partials/zulip.html b/docs/_templates/partials/zulip.html new file mode 100644 index 000000000..37e8a5b77 --- /dev/null +++ b/docs/_templates/partials/zulip.html @@ -0,0 +1,21 @@ + + Visit Zulip chatroom + + + + + + + + + diff --git a/docs/conf.py b/docs/conf.py index f107e0c8c..8981fff16 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -24,6 +24,7 @@ import logging from jinja2.filters import FILTERS +from sphinx_gallery import gen_rst from sphinx_gallery import scrapers from sphinx_gallery.sorting import ExampleTitleSortKey from sphinx.highlighting import lexers @@ -42,9 +43,9 @@ # -- Project information ----------------------------------------------------- -project = 'napari' -copyright = f'{datetime.now().year}, The napari team' -author = 'The napari team' +project = "napari" +copyright = f"{datetime.now().year}, The napari team" +author = "The napari team" # -- General configuration --------------------------------------------------- @@ -53,7 +54,7 @@ # ones. autosummary_generate = True autosummary_imported_members = True -comments_config = {'hypothesis': False, 'utterances': False} +comments_config = {"hypothesis": False, "utterances": False} # execution_allow_errors = False # execution_excludepatterns = [] @@ -67,7 +68,7 @@ "sphinx.ext.intersphinx", "sphinx_external_toc", "sphinx_design", - 'myst_nb', + "myst_nb", # "sphinx_comments", "sphinx.ext.viewcode", "sphinx_favicon", @@ -94,7 +95,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'napari_sphinx_theme' +html_theme = "pydata_sphinx_theme" # Define the json_url for our version switcher. json_url = "https://napari.org/dev/_static/version_switcher.json" @@ -109,7 +110,10 @@ {"name": "napari hub", "url": "https://napari-hub.org"}, {"name": "Island Dispatch", "url": "https://napari.org/island-dispatch"}, {"name": "Community chat", "url": "https://napari.zulipchat.com"}, - {"name": "workshop template", "url": "https://napari.org/napari-workshop-template"}, + { + "name": "workshop template", + "url": "https://napari.org/napari-workshop-template", + }, ], "github_url": "https://github.com/napari/napari", "navbar_start": ["navbar-logo", "navbar-project"], @@ -138,21 +142,21 @@ html_sidebars = { "**": ["search-field.html", "sidebar-nav-bs"], - "index": ["search-field.html" , "calendar-template"], + "index": ["search-field.html", "calendar-template"], } html_context = { - # use Light theme only, don't auto switch (default) - "default_mode": "light" + # use Light theme only, don't auto switch (default) + "default_mode": "light" } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] html_logo = "_static/images/logo.png" -html_sourcelink_suffix = '' -html_title = 'napari' +html_sourcelink_suffix = "" +html_title = "napari" favicons = [ { @@ -177,37 +181,37 @@ ] html_css_files = [ - 'custom.css', + "custom.css", ] intersphinx_mapping = { - 'python': ['https://docs.python.org/3', None], - 'numpy': ['https://numpy.org/doc/stable/', None], - 'napari_plugin_engine': [ - 'https://napari-plugin-engine.readthedocs.io/en/latest/', - 'https://napari-plugin-engine.readthedocs.io/en/latest/objects.inv', + "python": ["https://docs.python.org/3", None], + "numpy": ["https://numpy.org/doc/stable/", None], + "napari_plugin_engine": [ + "https://napari-plugin-engine.readthedocs.io/en/latest/", + "https://napari-plugin-engine.readthedocs.io/en/latest/objects.inv", ], - 'magicgui': [ - 'https://pyapp-kit.github.io/magicgui/', - 'https://pyapp-kit.github.io/magicgui/objects.inv', + "magicgui": [ + "https://pyapp-kit.github.io/magicgui/", + "https://pyapp-kit.github.io/magicgui/objects.inv", ], - 'app-model': [ - 'http://app-model.readthedocs.io/en/latest/', - 'http://app-model.readthedocs.io/en/latest/objects.inv', + "app-model": [ + "http://app-model.readthedocs.io/en/latest/", + "http://app-model.readthedocs.io/en/latest/objects.inv", ], - 'vispy': [ - 'https://vispy.org/', - 'https://vispy.org/objects.inv', + "vispy": [ + "https://vispy.org/", + "https://vispy.org/objects.inv", ], } myst_enable_extensions = [ - 'colon_fence', - 'dollarmath', - 'substitution', - 'tasklist', - 'attrs_inline', - 'linkify', + "colon_fence", + "dollarmath", + "substitution", + "tasklist", + "attrs_inline", + "linkify", ] myst_heading_anchors = 4 @@ -219,18 +223,26 @@ def get_supported_python_versions(project_name): based on the classifiers in its distribution metadata. """ dist = distribution(project_name) - classifiers = [value for key, value in dist.metadata.items() if key == 'Classifier' and value.startswith('Programming Language :: Python ::')] - return [parse_version(c.split(' :: ')[-1]) for c in classifiers if not c.endswith('Only')] + classifiers = [ + value + for key, value in dist.metadata.items() + if key == "Classifier" and value.startswith("Programming Language :: Python ::") + ] + return [ + parse_version(c.split(" :: ")[-1]) + for c in classifiers + if not c.endswith("Only") + ] -napari_supported_python_versions = get_supported_python_versions('napari') +napari_supported_python_versions = get_supported_python_versions("napari") min_python_version = min(napari_supported_python_versions) max_python_version = max(napari_supported_python_versions) -version_string = '.'.join(str(x) for x in __version_tuple__[:3]) +version_string = ".".join(str(x) for x in __version_tuple__[:3]) # when updating the version below, ensure to also update napari/napari README -python_version = '3.11' +python_version = "3.11" python_version_range = f"{min_python_version}-{max_python_version}" myst_substitutions = { @@ -244,31 +256,31 @@ def get_supported_python_versions(project_name): myst_footnote_transition = False -nb_output_stderr = 'show' +nb_output_stderr = "show" panels_add_bootstrap_css = False -pygments_style = 'solarized-dark' -suppress_warnings = ['myst.header', 'etoc.toctree', 'config.cache'] +pygments_style = "solarized-dark" +suppress_warnings = ["myst.header", "etoc.toctree", "config.cache"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = [ - '_build', - 'Thumbs.db', - '.DS_Store', - '.jupyter_cache', - 'jupyter_execute', - 'plugins/_*.md', - 'plugins/building_a_plugin/_layer_data_guide.md', - 'gallery/index.rst', + "_build", + "Thumbs.db", + ".DS_Store", + ".jupyter_cache", + "jupyter_execute", + "plugins/_*.md", + "plugins/building_a_plugin/_layer_data_guide.md", + "gallery/index.rst", ] -napoleon_custom_sections = [('Events', 'params_style')] -lexers['toml'] = TOMLLexer(startinline=True) +napoleon_custom_sections = [("Events", "params_style")] +lexers["toml"] = TOMLLexer(startinline=True) def reset_napari(gallery_conf, fname): @@ -276,7 +288,7 @@ def reset_napari(gallery_conf, fname): from qtpy.QtWidgets import QApplication settings = get_settings() - settings.appearance.theme = 'dark' + settings.appearance.theme = "dark" # Disabling `QApplication.exec_` means example scripts can call `exec_` # (scripts work when run normally) without blocking example execution by @@ -291,7 +303,7 @@ def napari_scraper(block, block_vars, gallery_conf): `app.processEvents()` allows Qt events to propagateo and prevents hanging. """ - imgpath_iter = block_vars['image_path_iterator'] + imgpath_iter = block_vars["image_path_iterator"] if app := napari.qt.get_qapp(): app.processEvents() @@ -309,10 +321,10 @@ def napari_scraper(block, block_vars, gallery_conf): napari.Viewer.close_all() app.processEvents() - return scrapers.figure_rst(img_paths, gallery_conf['src_dir']) + return scrapers.figure_rst(img_paths, gallery_conf["src_dir"]) -from sphinx_gallery import gen_rst +# -- Sphinx gallery gen_rst.EXAMPLE_HEADER = """ .. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. @@ -338,22 +350,25 @@ def napari_scraper(block, block_vars, gallery_conf): sphinx_gallery_conf = { # path to your example scripts (this value is set in the Makefile) # 'examples_dirs': '../../napari/examples', - 'gallery_dirs': 'gallery', # path to where to save gallery generated output - 'filename_pattern': '/*.py', - 'ignore_pattern': 'README.rst|/*_.py', - 'default_thumb_file': Path(__file__).parent / '_static' / 'images' / 'logo.png', - 'plot_gallery': "'True'", # https://github.com/sphinx-gallery/sphinx-gallery/pull/304/files - 'download_all_examples': False, - 'min_reported_time': 10, - 'only_warn_on_example_error': False, - 'abort_on_example_error': True, - 'image_scrapers': ("matplotlib", napari_scraper,), - 'reset_modules': (reset_napari,), - 'reference_url': {'napari': None}, - 'within_subsection_order': ExampleTitleSortKey, + "gallery_dirs": "gallery", # path to where to save gallery generated output + "filename_pattern": "/*.py", + "ignore_pattern": "README.rst|/*_.py", + "default_thumb_file": Path(__file__).parent / "_static" / "images" / "logo.png", + "plot_gallery": "'True'", # https://github.com/sphinx-gallery/sphinx-gallery/pull/304/files + "download_all_examples": False, + "min_reported_time": 10, + "only_warn_on_example_error": False, + "abort_on_example_error": True, + "image_scrapers": ( + "matplotlib", + napari_scraper, + ), + "reset_modules": (reset_napari,), + "reference_url": {"napari": None}, + "within_subsection_order": ExampleTitleSortKey, } -GOOGLE_CALENDAR_API_KEY = os.environ.get('GOOGLE_CALENDAR_API_KEY', '') +GOOGLE_CALENDAR_API_KEY = os.environ.get("GOOGLE_CALENDAR_API_KEY", "") def add_google_calendar_secrets(app, docname, source): @@ -363,8 +378,8 @@ def add_google_calendar_secrets(app, docname, source): source file. You can process the contents and replace this item to implement source-level transformations. """ - if docname == 'community/meeting_schedule': - source[0] = source[0].replace('{API_KEY}', GOOGLE_CALENDAR_API_KEY) + if docname == "community/meeting_schedule": + source[0] = source[0].replace("{API_KEY}", GOOGLE_CALENDAR_API_KEY) class FilterSphinxWarnings(logging.Filter): @@ -377,6 +392,7 @@ class FilterSphinxWarnings(logging.Filter): or rendering issues, so we can safely ignore them. """ + def __init__(self, app): self.app = app super().__init__() @@ -384,9 +400,7 @@ def __init__(self, app): def filter(self, record: logging.LogRecord) -> bool: msg = record.getMessage() - filter_out = ( - "duplicate object description", - ) + filter_out = ("duplicate object description",) if msg.strip().startswith(filter_out): return False @@ -417,14 +431,13 @@ def setup(app): """ app.registry.source_suffix.pop(".ipynb", None) - app.connect('source-read', add_google_calendar_secrets) - app.connect('linkcheck-process-uri', rewrite_github_anchor) - app.connect('autodoc-process-docstring', qt_docstrings) + app.connect("source-read", add_google_calendar_secrets) + app.connect("linkcheck-process-uri", rewrite_github_anchor) + app.connect("autodoc-process-docstring", qt_docstrings) logger = logging.getLogger("sphinx") warning_handler, *_ = [ - h for h in logger.handlers - if isinstance(h, sphinx_logging.WarningStreamHandler) + h for h in logger.handlers if isinstance(h, sphinx_logging.WarningStreamHandler) ] warning_handler.filters.insert(0, FilterSphinxWarnings(app)) @@ -449,7 +462,7 @@ def get_attributes(item, obj, modulename): autosummary_ignore_module_all = False -linkcheck_anchors_ignore = [r'^!', r'L\d+-L\d+', r'r\d+', r'issuecomment-\d+'] +linkcheck_anchors_ignore = [r"^!", r"L\d+-L\d+", r"r\d+", r"issuecomment-\d+"] linkcheck_ignore = [ "https://napari.zulipchat.com/", "../_tags", @@ -486,10 +499,10 @@ def rewrite_github_anchor(app, uri: str): ]: if parsed.fragment.startswith(text): return None - if re.match(r'r\d+', parsed.fragment): + if re.match(r"r\d+", parsed.fragment): return None - prefixed = parsed.fragment.startswith('user-content-') + prefixed = parsed.fragment.startswith("user-content-") if not prefixed: - fragment = f'user-content-{parsed.fragment}' + fragment = f"user-content-{parsed.fragment}" return urlunparse(parsed._replace(fragment=fragment)) return None From 050a94ffe4795c5748a038bb28f7646ca4ab7e8f Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Fri, 21 Feb 2025 17:50:37 -0800 Subject: [PATCH 04/21] Add css from napari-sphinx-theme --- docs/_static/napari-sphinx-theme.css | 970 +++++++++++++++++++++++++++ docs/conf.py | 2 + 2 files changed, 972 insertions(+) create mode 100644 docs/_static/napari-sphinx-theme.css diff --git a/docs/_static/napari-sphinx-theme.css b/docs/_static/napari-sphinx-theme.css new file mode 100644 index 000000000..b9919ef7e --- /dev/null +++ b/docs/_static/napari-sphinx-theme.css @@ -0,0 +1,970 @@ +/*************************** + napari custom colors +***************************/ +@import url("https://fonts.googleapis.com/css2?family=Barlow:wght@400;500;600;700&display=swap"); + +html { + --napari-primary-blue: #80d1ff; + --napari-deep-blue: #009bf2; + --napari-light-blue: #d2efff; + --napari-dark-gray: #686868; + --napari-gray: #f7f7f7; + --pst-font-family-base: "Barlow", var(--pst-font-family-base-system); + --pst-font-family-heading: "Barlow", var(--pst-font-family-base-system); + --pst-font-family-monospace: "JetBrains Mono", + var(--pst-font-family-monospace-system); + --pst-font-size-base: 16px; + --pst-color-headerlink: var(--napari-dark-gray); + --pst-color-headerlink-hover: var(--napari-deep-blue); + --pst-color-surface: var(--napari-gray) !important; +} + +html[data-theme="light"] { + --pst-color-primary: black; + --pst-color-secondary: var(--napari-primary-blue); + --pst-color-background: white; + --napari-color-text-base: black; + --pst-color-text-base: var(--napari-color-text-base); + --pst-color-link: black; + --pst-color-link-hover: black !important; + --pst-color-inline-code: black !important; + --pst-color-inline-code-links: black !important; + --pst-color-on-background: white; + --pst-color-text-muted: var(--napari-dark-gray); + --pst-color-border: var(--napari-gray); + --pst-color-target: var(--napari-gray); +} + +/* Dark theme is currently unset - design/accessibility assessment is needed here */ +html[data-theme="dark"] { + --pst-color-primary: black; + --pst-color-secondary: var(--napari-primary-blue); + --pst-color-background: white; + --napari-color-text-base: black; + --pst-color-text-base: var(--napari-color-text-base); + --pst-color-link: black; + --pst-color-link-hover: black !important; + --pst-color-inline-code: black !important; + --pst-color-inline-code-links: black !important; + --pst-color-on-background: white; + --pst-color-text-muted: var(--napari-dark-gray); + --pst-color-border: var(--napari-gray); + --pst-color-target: var(--napari-gray); + --pst-color-secondary-bg: #e0c7ff; + --pst-color-primary-text: white; +} + +body { + margin: 0; + font-family: + "Barlow", + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Roboto, + "Helvetica Neue", + Arial, + "Noto Sans", + "Liberation Sans", + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", + "Noto Color Emoji"; + text-align: left; +} + +p, +.line-block .line { + line-height: 1.5; + font-size: 1.0625rem; +} + +h1 { + font-size: 2.1875rem; + line-height: 125%; + font-weight: bolder; +} + +/*************************** + napari footer +***************************/ + +.napari-footer { + display: flex; + flex-shrink: 0; + flex-direction: row; + flex-wrap: wrap; + width: 100%; + align-items: center; + justify-content: space-between; + background-color: black; + padding-top: 1.5rem; + padding-bottom: 0.5rem; + margin-top: 75px; +} + +@media (min-width: 495px) { + .napari-footer { + padding-left: 3rem; + padding-right: 3rem; + } + + .napari-footer a > span { + font-size: 0.875rem; + line-height: 1.25rem; + } +} + +.napari-footer p { + color: white; +} + +.napari-footer a { + white-space: nowrap; + text-decoration-line: none; + margin-right: 1rem; + margin-bottom: 1rem; + color: white !important; + display: flex; + flex-direction: row; + align-items: center; +} + +.napari-footer a:hover { + color: white; +} + +.napari-footer a:last-child { + margin-right: 0px; +} + +.napari-footer a > svg { + margin-right: 0.25rem; + display: inline-block; + height: 1em; + width: 1em; +} + +.napari-footer .footer-item { + display: flex; + flex-wrap: wrap; + align-items: center; +} + +.napari-footer .footer-item { + display: flex; + flex-wrap: wrap; + align-items: center; +} + +.napari-footer .footer-item--with-napari-copyright { + width: 100%; + justify-content: flex-end; +} + +.napari-footer .napari-copyright { + display: flex; + flex-direction: column; +} + +.napari-footer .napari-copyright, +.napari-footer .napari-copyright .copyright { + font-weight: 600; + font-size: 0.5625rem; + margin-bottom: auto; +} + +@media (min-width: 780px) { + .napari-footer .footer-item--with-napari-copyright { + width: max-content; + } + + .napari-footer .footer-item--with-napari-copyright { + justify-content: flex-start; + } +} + +@media (min-width: 495px) { + .napari-footer .napari-copyright, + .napari-footer .napari-copyright .copyright { + font-size: 0.875rem; + line-height: 1.25rem; + } +} + +.napari-footer .napari-copyright .sphinx-link, +.napari-footer .napari-copyright .sphinx-version { + display: flex; + justify-content: flex-start; +} + +.napari-footer + .napari-copyright + .sphinx-link + > :not([hidden]) + ~ :not([hidden]) { + margin-right: calc(0.25rem); + margin-left: calc(0.25rem); +} + +.napari-footer .napari-copyright .sphinx-version { + color: white; +} + +.napari-footer .footer-icon__hover-blue .footer-icon__light-blue { + display: none; +} + +.napari-footer .footer-icon__hover-blue:hover .footer-icon__regular { + display: none; +} + +.napari-footer .footer-icon__hover-blue:hover .footer-icon__light-blue { + display: block; +} + +/* Recommended by PST */ +.footer-items__start, +.footer-items__end { + flex-direction: row; +} + +.bd-footer__inner { + display: flex; + flex-shrink: 0; + flex-direction: row; + flex-wrap: wrap; + width: 100%; + max-width: 100%; + align-items: center; + justify-content: space-between; + background-color: black; +} + +/**************************** + Nav bar section +*****************************/ + +.navbar { + background-color: var(--napari-primary-blue) !important; + box-shadow: none; +} + +.navbar-brand { + vertical-align: middle; + font-size: 1.25rem; + color: black !important; + position: relative; + font-weight: bolder; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none !important; + color: var(--napari-color-text-base) !important; +} + +/* Navbar text */ +.bd-header ul.navbar-nav > li.nav-item > .nav-link { + color: var(--napari-color-text-base); + font-size: 1.0625rem; + font-weight: 500 !important; + border-bottom: 3px solid transparent; + padding: 16px 1.0625rem 16px !important; +} + +.bd-header ul.navbar-nav > li.nav-item > .nav-link:hover { + color: var(--napari-color-text-base); + font-size: 1.0625rem; + font-weight: 500 !important; + border-bottom: 3px solid var(--napari-color-text-base); +} + +.bd-header ul.navbar-nav > li.nav-item.current > .nav-link::before { + border-bottom: 0px solid var(--napari-color-text-base); +} + +.bd-header ul.navbar-nav > li.nav-item.current > .nav-link { + border-bottom: 3px solid var(--napari-color-text-base); + font-weight: 700 !important; +} + +.bd-header ul.navbar-nav { + height: var(--pst-header-height); +} + +.bd-header ul.navbar-nav > li.nav-item { + margin-inline: 0px; +} + +.bd-header ul.navbar-nav > li.nav-item.dropdown > .dropdown-toggle { + color: var(--napari-color-text-base); + font-size: 1.0625rem; + font-weight: 500 !important; + border-bottom: 3px solid transparent; + padding: 16px 1.0625rem 16px !important; + height: var(--pst-header-height); +} + +.bd-header ul.navbar-nav > li.nav-item.dropdown > .dropdown-toggle:hover { + box-shadow: none; + text-decoration: none; + border-bottom: 3px solid var(--napari-color-text-base); +} + +.bd-header ul.navbar-nav li a.nav-link.dropdown-item { + color: var(--napari-color-text-base); + font-weight: 500; +} + +html .pst-navbar-icon, +html .pst-navbar-icon:hover { + color: var(--napari-color-text-base); +} + +/*************************** + version switcher +***************************/ + +button.btn.version-switcher__button { + padding-top: 0px; + font-size: 0.875rem; + font-weight: 600; + border-style: none; + color: var(--napari-color-text-base); +} + +button.btn.version-switcher__button:hover { + color: var(--napari-color-text-base); +} + +.version-switcher__menu a.list-group-item { + background-color: var(--pst-color-background); + color: var(--napari-color-text-base); + padding: 0.5rem 0.5rem; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + font-size: 0.875rem; +} + +.version-switcher__menu a.list-group-item:hover { + color: var(--napari-color-text-base); +} + +.version-switcher__menu, +button.version-switcher__button { + min-width: max-content; + border-radius: unset; +} + +/*************************** + sidebar +***************************/ + +/* Remove "Section Navigation" caption */ +.bd-links__title { + display: none; +} + +/* Move chevron to the left */ +.bd-sidebar-primary li.has-children > details > summary .toctree-toggle { + right: unset; +} + +/* Fonts and styles */ +.bd-sidebar a.reference, +.bd-sidebar .caption-text { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.bd-sidebar-primary .sidebar-primary-items__end { + margin-bottom: 0; + margin-top: 0; +} + +.bd-sidebar .toctree-l1 a { + padding-left: 32px; +} + +.bd-sidebar .toctree-l2 { + margin-left: -0.2rem; + border-left: 1px solid var(--napari-color-text-base); +} + +.bd-sidebar .toctree-l2 label { + left: 4px; +} + +.bd-sidebar .toctree-l2 a { + font-size: 0.875rem; + line-height: 1.5rem; + text-decoration-line: none; + border-left: 2px solid transparent; + color: var(--napari-color-text-base) !important; +} + +.bd-sidebar .toctree-l2 a:hover, +.bd-sidebar .toctree-l2 a.current:hover { + border-left: 2px solid var(--napari-primary-blue); +} + +.bd-sidebar .toctree-l2 a.current { + border-left: 2px solid var(--napari-color-text-base); +} + +.bd-sidebar .toctree-l3 label { + left: 6px; +} + +.bd-sidebar .toctree-l3 a { + font-size: 0.875rem; + line-height: 1.5rem; + text-decoration-line: none; + border-left: 2px solid transparent; + color: var(--napari-color-text-base) !important; + padding-left: 36px; +} + +.bd-sidebar .toctree-l3 a:hover, +.bd-sidebar .toctree-l3 a.current:hover { + border-left: 2px solid var(--napari-primary-blue); + margin-left: -1rem; + padding-left: 52px; +} + +.bd-sidebar .toctree-l3 a.current { + border-left: 2px solid var(--napari-color-text-base); + margin-left: -1rem; + padding-left: 52px; +} + +.bd-sidebar .toctree-l4 label { + left: 8px; +} + +.bd-sidebar .toctree-l4 a { + font-size: 0.875rem; + line-height: 1.5rem; + text-decoration-line: none; + border-left: 2px solid transparent; + color: var(--napari-color-text-base) !important; +} + +.bd-sidebar .toctree-l4 a:hover, +.bd-sidebar .toctree-l4 a.current:hover { + border-left: 2px solid var(--napari-primary-blue); + margin-left: -2rem; + padding-left: 68px; +} + +.bd-sidebar .toctree-l4 a.current { + border-left: 2px solid var(--napari-color-text-base); + margin-left: -2rem; + padding-left: 68px; +} + +.bd-sidebar .toctree-l5 label { + left: 10px; +} + +.bd-sidebar .toctree-l5 a { + font-size: 0.875rem; + line-height: 1.5rem; + text-decoration-line: none; + border-left: 2px solid transparent; + color: var(--napari-color-text-base) !important; +} + +.bd-sidebar .toctree-l5 a:hover, +.bd-sidebar .toctree-l5 a.current:hover { + border-left: 2px solid var(--napari-primary-blue); +} + +.bd-sidebar .toctree-l5 a.current { + border-left: 2px solid var(--napari-color-text-base); +} + +.navbar-nav li a:focus, +.navbar-nav li a:hover, +.navbar-nav li.current > a { + color: var(--napari-color-text-base); +} + +nav.bd-links li > a { + color: var(--napari-color-text-base); + display: block; + line-height: 1.25rem; +} + +nav.bd-links li > a:active, +nav.bd-links li > a:hover { + color: var(--napari-color-text-base); +} + +nav.bd-links li > a:hover { + text-decoration: none !important; +} + +nav.bd-links .current > a { + box-shadow: none !important; +} + +/*************************** +search +***************************/ + +.bd-search { + border: 1px solid transparent; +} + +.bd-search:focus-within { + box-shadow: 0 0 0 0.1875rem var(--napari-primary-blue); +} + +.form-control { + border: 1px transparent; +} + +.form-control:focus, +.form-control:focus-visible { + background-color: var(--pst-color-background); + border: none; + box-shadow: none; + color: var(--pst-color-text-muted); + outline: none; +} + +/*************************** +page toc sidebar +***************************/ + +.onthispage { + border-style: none; + padding: 0px; + padding-top: 1px; + padding-bottom: 5px; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 600; + text-transform: uppercase; + color: var(--napari-color-text-base) !important; + margin: 0 !important; +} + +.page-toc { + .section-nav { + padding-left: 0; + border-bottom: none; + } + + .onthispage { + color: var(--napari-color-text-base); + font-weight: var(--pst-sidebar-header-font-weight); + margin-bottom: 1rem; + } +} + +.toc-entry a.nav-link.active:hover { + color: var(--napari-color-text-base); +} + +.toc-entry a.nav-link:active, +.toc-entry a.nav-link:hover { + color: var(--napari-color-text-base); +} + +nav.page-toc { + border-left: 1px solid var(--napari-color-text-base); + padding-left: 1rem; +} + +.sidebar-secondary-item { + border-left: none !important; +} + +.toc-entry a.nav-link, +.toc-entry a > code { + color: var(--napari-color-text-base); +} + +.toc-entry > .nav-link { + border-left: 3px solid transparent; +} + +.toc-entry > .nav-link:hover { + border-left: 3px solid var(--napari-primary-blue); +} + +.toc-entry a.nav-link:hover { + text-decoration: none !important; +} + +.toc-entry a.nav-link.active { + box-shadow: none !important; + border-left: 3px solid var(--napari-color-text-base); +} + +.toc-h3.nav-item.toc-entry.active a { + margin-left: -2rem; + padding-left: 2rem; +} + +.toc-h3.nav-item.toc-entry a { + margin-left: -2rem; + padding-left: 2rem; +} + +.toc-h4.nav-item.toc-entry.active a { + margin-left: -3rem; + padding-left: 3rem; +} + +.toc-h4.nav-item.toc-entry a { + margin-left: -3rem; + padding-left: 3rem; +} + +.toc-h4.nav-item.toc-entry a:hover { + margin-left: -3rem; + padding-left: 3rem; +} + +/*************************** + napari calendar +***************************/ + +:root { + --fc-border-color: var(--napari-primary-blue); + --fc-daygrid-event-dot-width: 5px; + --fc-button-bg-color: var(--napari-primary-blue); + --fc-button-border-color: var(--napari-primary-blue); + --fc-button-text-color: var(--napari-color-text-base); + --fc-button-active-bg-color: var(--napari-deep-blue); + --fc-button-active-border-color: var(--napari-deep-blue); + --fc-button-hover-bg-color: var(--napari-deep-blue); + --fc-button-hover-border-color: var(--napari-deep-blue); + --fc-event-bg-color: var(--napari-light-blue); + --fc-event-border-color: var(--napari-light-blue); + --fc-event-text-color: var(--napari-color-text-base); +} + +.fc .fc-button:focus { + box-shadow: none; +} + +.fc-event-time { + margin-right: 3px; + min-width: fit-content; +} + +.fc-day-today .fc-daygrid-day-number { + background-color: var(--napari-primary-blue); +} + +.fc .fc-daygrid-day.fc-day-today { + background-color: unset; +} + +/*************************** + Textual elements +***************************/ + +h1 { + font-weight: 700; + color: var(--napari-color-text-base) !important; +} + +h2 { + font-weight: 700; + color: var(--napari-color-text-base) !important; +} + +h3 { + font-weight: 700; + color: var(--napari-color-text-base) !important; +} + +h4 { + font-weight: 700; + color: var(--napari-color-text-base) !important; +} + +h5 { + font-weight: 700; + color: var(--napari-color-text-base) !important; +} + +h6 { + font-weight: 700; + color: var(--napari-color-text-base) !important; +} + +a.headerlink { + color: var(--napari-dark-gray); +} + +.sd-card-hover:hover { + border-color: var(--napari-color-text-base) !important; + transform: scale(1.01); +} + +.prev-next-area p { + color: var(--napari-color-text-base); +} + +/*************************** + Admonitions +***************************/ + +.admonition, +div.admonition { + --color: #80d1ff; + border: var(--color) solid 1px !important; + border-radius: 0 !important; + box-shadow: none !important; + border-color: rgba(var(--pst-color-admonition-default), 1); + padding-left: 0 !important; + font-size: 0.938rem; + font-weight: 500; +} + +.admonition > .admonition-title, +div.admonition > .admonition-title { + text-transform: uppercase; + background: var(--color) !important; + font-size: 0.938rem !important; + font-weight: 700; +} + +/* Remove admonition title icon */ +div.admonition > .admonition-title:after, +.admonition > .admonition-title:after { + display: none; +} + +/* Padding and spacing */ +div.admonition.warning > ul.simple { + padding: 1.1rem !important; +} + +div.admonition > p, +div.admonition > ul.simple p { + font-size: 0.938rem; +} + +div.admonition > p { + padding-top: 0.5rem; + padding-bottom: 0.4rem; +} + +/* Toggle button */ +.admonition.toggle-hidden { + height: 40px; +} + +.admonition .toggle-button { + top: 0px; + right: 0px; + z-index: 10; + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + float: unset; +} + +.admonition .toggle-button::before { + display: none; +} + +.admonition .toggle-button svg { + transition-property: transform; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + transform: rotate(45deg); +} + +.admonition .toggle-button.toggle-button-hidden svg { + transform: rotate(0); +} + +/* Attention */ + +.admonition.attention { + --color: #d8f97d; +} + +/* Caution */ + +.admonition.caution { + --color: #ffc580; +} + +/* Warning */ + +.admonition.warning { + --color: #ffa680; +} + +/* Danger */ + +.admonition.danger { + --color: #ff8080; +} + +/* Error */ + +.admonition.error { + --color: #fade7d; +} + +/* Hint */ + +.admonition.hint { + --color: #8094ff; +} + +/* Tip */ + +.admonition.tip { + --color: #cf80ff; +} + +/* Important */ + +.admonition.important { + --color: #f1f379; +} + +/* Note */ + +.admonition.note { + --color: #80ffe0; +} + +/*************************** + Page container +***************************/ + +#pst-back-to-top { + background-color: var(--napari-light-blue); + color: var(--napari-dark-gray); +} + +/*************************** + Calendar popup +***************************/ + +/* The Modal (background) */ +.modal { + /* Hidden by default */ + position: fixed; + /* Stay in place */ + z-index: 1; + /* Sit on top */ + padding-top: 100px; + /* Location of the box */ + left: 0; + top: 0; + width: 100%; + /* Full width */ + height: 100%; + /* Full height */ + overflow: auto; + /* Enable scroll if needed */ + background-color: rgb(0, 0, 0); + /* Fallback color */ + background-color: rgba(0, 0, 0, 0.4); + /* Black w/ opacity */ +} + +/* Modal Content */ +.modal-content { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: #fefefe; + margin: auto; + padding: 0px; + border: 1px solid #888; + box-shadow: + 0 4px 8px 0 rgba(0, 0, 0, 0.2), + 0 6px 20px 0 rgba(0, 0, 0, 0.19); +} + +/* Modal Content */ +.modal-content { + width: 30%; +} + +@media (max-width: 780px) { + .modal-content { + width: 50%; + } +} + +@media (max-width: 495px) { + .modal-content { + width: 80%; + } +} + +/* Add Animation */ +@-webkit-keyframes animatetop { + from { + top: -300px; + opacity: 0; + } + + to { + top: 0; + opacity: 1; + } +} + +@keyframes animatetop { + from { + top: -300px; + opacity: 0; + } + + to { + top: 0; + opacity: 1; + } +} + +/* The Close Button */ +.close { + color: white; + float: right; + font-size: 28px; + font-weight: bold; + padding-right: 12px; + padding-top: 4px; +} + +.close:hover, +.close:focus { + color: #000; + text-decoration: none; + cursor: pointer; +} + +.modal-header { + padding: 0px 0px 0px 12px; + background-color: var(--napari-primary-blue); + color: white; + display: block; +} + +.modal-header h3 { + margin-top: 1rem; +} + +.modal-body { + padding: 12px; +} diff --git a/docs/conf.py b/docs/conf.py index 8981fff16..f0e480b33 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -182,11 +182,13 @@ html_css_files = [ "custom.css", + "napari-sphinx-theme.css", ] intersphinx_mapping = { "python": ["https://docs.python.org/3", None], "numpy": ["https://numpy.org/doc/stable/", None], + # napari_plugin_engine is deprecated "napari_plugin_engine": [ "https://napari-plugin-engine.readthedocs.io/en/latest/", "https://napari-plugin-engine.readthedocs.io/en/latest/objects.inv", From a2f60c696b9b67419cd06f56a379aadd53c852a1 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 08:24:00 -0800 Subject: [PATCH 05/21] Move back to where to test build --- docs/_templates/footer.html | 23 +++++++++ docs/_templates/search-button-field.html | 10 ++++ docs/_templates/search-field.html | 21 ++++++++ docs/conf.py | 64 ++++++++---------------- 4 files changed, 74 insertions(+), 44 deletions(-) create mode 100644 docs/_templates/footer.html create mode 100644 docs/_templates/search-button-field.html create mode 100644 docs/_templates/search-field.html diff --git a/docs/_templates/footer.html b/docs/_templates/footer.html new file mode 100644 index 000000000..ff6eee7b2 --- /dev/null +++ b/docs/_templates/footer.html @@ -0,0 +1,23 @@ +{% if theme_footer_start or theme_footer_center or theme_footer_end %} + +{% endif %} diff --git a/docs/_templates/search-button-field.html b/docs/_templates/search-button-field.html new file mode 100644 index 000000000..6ca02fb32 --- /dev/null +++ b/docs/_templates/search-button-field.html @@ -0,0 +1,10 @@ +{# Behaves the same as `search-button.html` but looks more like a search field. +# # As this function will only work when JavaScript is enabled, we add it +through JavaScript. #} + diff --git a/docs/_templates/search-field.html b/docs/_templates/search-field.html new file mode 100644 index 000000000..ab2682b1c --- /dev/null +++ b/docs/_templates/search-field.html @@ -0,0 +1,21 @@ +{# A bootstrap-styled field that will direct to the `search.html` page when +submitted #} + diff --git a/docs/conf.py b/docs/conf.py index f0e480b33..5f1a429c4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -4,80 +4,62 @@ # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - -import re +import logging import os +import re from datetime import datetime from importlib import import_module from importlib.metadata import distribution from pathlib import Path from urllib.parse import urlparse, urlunparse -import logging from jinja2.filters import FILTERS +from packaging.version import parse as parse_version +from pygments.lexers import TOMLLexer from sphinx_gallery import gen_rst from sphinx_gallery import scrapers from sphinx_gallery.sorting import ExampleTitleSortKey from sphinx.highlighting import lexers from sphinx.util import logging as sphinx_logging -from packaging.version import parse as parse_version -from pygments.lexers import TOMLLexer import napari from napari._version import __version_tuple__ -release = napari.__version__ -if "dev" in release: - version = "dev" -else: - version = release - # -- Project information ----------------------------------------------------- project = "napari" copyright = f"{datetime.now().year}, The napari team" author = "The napari team" -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -autosummary_generate = True -autosummary_imported_members = True -comments_config = {"hypothesis": False, "utterances": False} +release = napari.__version__ +if "dev" in release: + version = "dev" +else: + version = release -# execution_allow_errors = False -# execution_excludepatterns = [] -# execution_in_temp = False -# execution_timeout = 30 +# -- General configuration --------------------------------------------------- +# Add sphinx extensions here extensions = [ - "sphinx.ext.napoleon", "sphinx.ext.autodoc", "sphinx.ext.autosummary", "sphinx.ext.intersphinx", - "sphinx_external_toc", - "sphinx_design", - "myst_nb", - # "sphinx_comments", + "sphinx.ext.napoleon", "sphinx.ext.viewcode", - "sphinx_favicon", + "myst_nb", "sphinx_copybutton", + "sphinx_design", + "sphinx_external_toc", + "sphinx_favicon", "sphinx_gallery.gen_gallery", "sphinx_tags", "sphinxcontrib.mermaid", ] +autosummary_generate = True +autosummary_imported_members = True +autosummary_ignore_module_all = False + external_toc_path = "_toc.yml" external_toc_exclude_missing = False @@ -92,9 +74,6 @@ # -- Options for HTML output ------------------------------------------------- -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# html_theme = "pydata_sphinx_theme" # Define the json_url for our version switcher. @@ -392,7 +371,6 @@ class FilterSphinxWarnings(logging.Filter): The warnings are not useful - they don't result in any missing documentation or rendering issues, so we can safely ignore them. - """ def __init__(self, app): @@ -462,8 +440,6 @@ def get_attributes(item, obj, modulename): FILTERS["get_attributes"] = get_attributes -autosummary_ignore_module_all = False - linkcheck_anchors_ignore = [r"^!", r"L\d+-L\d+", r"r\d+", r"issuecomment-\d+"] linkcheck_ignore = [ "https://napari.zulipchat.com/", From ac066cb2c04f1b5eca75e4b73b05a869f30e3398 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 08:44:22 -0800 Subject: [PATCH 06/21] Add layout template for footer --- docs/_templates/layout.html | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 docs/_templates/layout.html diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html new file mode 100644 index 000000000..a715e0f18 --- /dev/null +++ b/docs/_templates/layout.html @@ -0,0 +1,3 @@ +{%- extends "pydata_sphinx_theme/layout.html" %} {%- block footer %} +
{%- include "footer.html" %}
+{%- endblock %} From c63223911a983537966af8db2772b2d7c747e747 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 09:43:53 -0800 Subject: [PATCH 07/21] Combine css pass #1 --- docs/_static/custom.css | 995 ++++++++++++++++++++++++++- docs/_static/napari-sphinx-theme.css | 970 -------------------------- 2 files changed, 989 insertions(+), 976 deletions(-) delete mode 100644 docs/_static/napari-sphinx-theme.css diff --git a/docs/_static/custom.css b/docs/_static/custom.css index ecd8fabcf..3ac83927c 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,3 +1,5 @@ +@import url("https://fonts.googleapis.com/css2?family=Barlow:wght@400;500;600;700&display=swap"); + /* Sphinx-Gallery has compatible CSS to fix default sphinx themes Tested for Sphinx 1.3.1 for all themes: default, alabaster, sphinxdoc, @@ -6,7 +8,11 @@ Tested for Read the Docs theme 0.1.7 */ div.sphx-glr-download a { background-color: rgb(255, 255, 255) !important; - background-image: linear-gradient(to bottom, rgb(255, 255, 255), #ffffff) !important; + background-image: linear-gradient( + to bottom, + rgb(255, 255, 255), + #ffffff + ) !important; border-radius: 4px; border: 1px solid #ffffff !important; color: #000; @@ -17,7 +23,8 @@ div.sphx-glr-download a { } div.sphx-glr-download a:hover { - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 5px rgba(0, 0, 0, 0.25); text-decoration: none; background-image: none; @@ -25,18 +32,26 @@ div.sphx-glr-download a:hover { } /* Workaround for https: //github.com/napari/docs/pull/423#issuecomment-2141165872 */ -.bd-content .sd-tab-set>label { +.bd-content .sd-tab-set > label { background-color: var(--napari-gray); color: #222832; } /* Version warning banner color */ #bd-header-version-warning { - background-color: color-mix(in srgb, var(--pst-color-secondary-bg), transparent 30%); + background-color: color-mix( + in srgb, + var(--pst-color-secondary-bg), + transparent 30% + ); } #bd-header-version-warning .pst-button-link-to-stable-version { - background-color: color-mix(in srgb, var(--pst-color-secondary-bg), transparent 0%); + background-color: color-mix( + in srgb, + var(--pst-color-secondary-bg), + transparent 0% + ); border-color: var(--pst-color-secondary-bg); color: #222832; font-weight: 700; @@ -47,4 +62,972 @@ div.sphx-glr-download a:hover { border-color: var(--pst-color-secondary-bg); color: #222832; font-weight: 700; -} \ No newline at end of file +} + +/*************************** + napari custom colors +***************************/ + +html { + --napari-primary-blue: #80d1ff; + --napari-deep-blue: #009bf2; + --napari-light-blue: #d2efff; + --napari-dark-gray: #686868; + --napari-gray: #f7f7f7; + --pst-font-family-base: "Barlow", var(--pst-font-family-base-system); + --pst-font-family-heading: "Barlow", var(--pst-font-family-base-system); + --pst-font-family-monospace: "JetBrains Mono", + var(--pst-font-family-monospace-system); + --pst-font-size-base: 16px; + --pst-color-headerlink: var(--napari-dark-gray); + --pst-color-headerlink-hover: var(--napari-deep-blue); + --pst-color-surface: var(--napari-gray) !important; +} + +html[data-theme="light"] { + --pst-color-primary: black; + --pst-color-secondary: var(--napari-primary-blue); + --pst-color-background: white; + --napari-color-text-base: black; + --pst-color-text-base: var(--napari-color-text-base); + --pst-color-link: black; + --pst-color-link-hover: black !important; + --pst-color-inline-code: black !important; + --pst-color-inline-code-links: black !important; + --pst-color-on-background: white; + --pst-color-text-muted: var(--napari-dark-gray); + --pst-color-border: var(--napari-gray); + --pst-color-target: var(--napari-gray); +} + +/* Dark theme is currently unset - design/accessibility assessment is needed here */ +html[data-theme="dark"] { + --pst-color-primary: black; + --pst-color-secondary: var(--napari-primary-blue); + --pst-color-background: white; + --napari-color-text-base: black; + --pst-color-text-base: var(--napari-color-text-base); + --pst-color-link: black; + --pst-color-link-hover: black !important; + --pst-color-inline-code: black !important; + --pst-color-inline-code-links: black !important; + --pst-color-on-background: white; + --pst-color-text-muted: var(--napari-dark-gray); + --pst-color-border: var(--napari-gray); + --pst-color-target: var(--napari-gray); + --pst-color-secondary-bg: #e0c7ff; + --pst-color-primary-text: white; +} + +/* HTML elements */ +body { + margin: 0; + font-family: + "Barlow", + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Roboto, + "Helvetica Neue", + Arial, + "Noto Sans", + "Liberation Sans", + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji", + "Segoe UI Symbol", + "Noto Color Emoji"; + text-align: left; +} + +p, +.line-block .line { + line-height: 1.5; + font-size: 1.0625rem; +} + +h1 { + font-size: 2.1875rem; + line-height: 125%; + font-weight: bolder; +} + +/*************************** + Textual elements +***************************/ + +h1 { + font-weight: 700; + color: var(--napari-color-text-base) !important; +} + +h2 { + font-weight: 700; + color: var(--napari-color-text-base) !important; +} + +h3 { + font-weight: 700; + color: var(--napari-color-text-base) !important; +} + +h4 { + font-weight: 700; + color: var(--napari-color-text-base) !important; +} + +h5 { + font-weight: 700; + color: var(--napari-color-text-base) !important; +} + +h6 { + font-weight: 700; + color: var(--napari-color-text-base) !important; +} + +a.headerlink { + color: var(--napari-dark-gray); +} + +.sd-card-hover:hover { + border-color: var(--napari-color-text-base) !important; + transform: scale(1.01); +} + +.prev-next-area p { + color: var(--napari-color-text-base); +} + +/*************************** + napari footer +***************************/ + +.napari-footer { + display: flex; + flex-shrink: 0; + flex-direction: row; + flex-wrap: wrap; + width: 100%; + align-items: center; + justify-content: space-between; + background-color: black; + padding-top: 1.5rem; + padding-bottom: 0.5rem; + margin-top: 75px; +} + +@media (min-width: 495px) { + .napari-footer { + padding-left: 3rem; + padding-right: 3rem; + } + + .napari-footer a > span { + font-size: 0.875rem; + line-height: 1.25rem; + } +} + +.napari-footer p { + color: white; +} + +.napari-footer a { + white-space: nowrap; + text-decoration-line: none; + margin-right: 1rem; + margin-bottom: 1rem; + color: white !important; + display: flex; + flex-direction: row; + align-items: center; +} + +.napari-footer a:hover { + color: white; +} + +.napari-footer a:last-child { + margin-right: 0; +} + +.napari-footer a > svg { + margin-right: 0.25rem; + display: inline-block; + height: 1em; + width: 1em; +} + +.napari-footer .footer-item { + display: flex; + flex-wrap: wrap; + align-items: center; +} + +.napari-footer .footer-item { + display: flex; + flex-wrap: wrap; + align-items: center; +} + +.napari-footer .footer-item--with-napari-copyright { + width: 100%; + justify-content: flex-end; +} + +.napari-footer .napari-copyright { + display: flex; + flex-direction: column; +} + +.napari-footer .napari-copyright, +.napari-footer .napari-copyright .copyright { + font-weight: 600; + font-size: 0.5625rem; + margin-bottom: auto; +} + +@media (min-width: 780px) { + .napari-footer .footer-item--with-napari-copyright { + width: max-content; + } + + .napari-footer .footer-item--with-napari-copyright { + justify-content: flex-start; + } +} + +@media (min-width: 495px) { + .napari-footer .napari-copyright, + .napari-footer .napari-copyright .copyright { + font-size: 0.875rem; + line-height: 1.25rem; + } +} + +.napari-footer .napari-copyright .sphinx-link, +.napari-footer .napari-copyright .sphinx-version { + display: flex; + justify-content: flex-start; +} + +.napari-footer, +.napari-copyright, +.sphinx-link, +> :not([hidden]), +~ :not([hidden]) { + margin-right: calc(0.25rem); + margin-left: calc(0.25rem); +} + +.napari-footer .napari-copyright .sphinx-version { + color: white; +} + +.napari-footer .footer-icon__hover-blue .footer-icon__light-blue { + display: none; +} + +.napari-footer .footer-icon__hover-blue:hover .footer-icon__regular { + display: none; +} + +.napari-footer .footer-icon__hover-blue:hover .footer-icon__light-blue { + display: block; +} + +/* Recommended by PST */ +.footer-items__start, +.footer-items__end { + flex-direction: row; +} + +.bd-footer__inner { + display: flex; + flex-shrink: 0; + flex-direction: row; + flex-wrap: wrap; + width: 100%; + max-width: 100%; + align-items: center; + justify-content: space-between; + background-color: black; +} + +/**************************** + Nav bar section +*****************************/ + +.navbar { + background-color: var(--napari-primary-blue) !important; + box-shadow: none; +} + +.navbar-brand { + vertical-align: middle; + font-size: 1.25rem; + color: black !important; + position: relative; + font-weight: bolder; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none !important; + color: var(--napari-color-text-base) !important; +} + +/* Navbar text */ +.bd-header ul.navbar-nav > li.nav-item > .nav-link { + color: var(--napari-color-text-base); + font-size: 1.0625rem; + font-weight: 500 !important; + border-bottom: 3px solid transparent; + padding: 16px 1.0625rem 16px !important; +} + +.bd-header ul.navbar-nav > li.nav-item > .nav-link:hover { + color: var(--napari-color-text-base); + font-size: 1.0625rem; + font-weight: 500 !important; + border-bottom: 3px solid var(--napari-color-text-base); +} + +.bd-header ul.navbar-nav > li.nav-item.current > .nav-link::before { + border-bottom: 0 solid var(--napari-color-text-base); +} + +.bd-header ul.navbar-nav > li.nav-item.current > .nav-link { + border-bottom: 3px solid var(--napari-color-text-base); + font-weight: 700 !important; +} + +.bd-header ul.navbar-nav { + height: var(--pst-header-height); +} + +.bd-header ul.navbar-nav > li.nav-item { + margin-inline: 0; +} + +.bd-header ul.navbar-nav > li.nav-item.dropdown > .dropdown-toggle { + color: var(--napari-color-text-base); + font-size: 1.0625rem; + font-weight: 500 !important; + border-bottom: 3px solid transparent; + padding: 16px 1.0625rem 16px !important; + height: var(--pst-header-height); +} + +.bd-header ul.navbar-nav > li.nav-item.dropdown > .dropdown-toggle:hover { + box-shadow: none; + text-decoration: none; + border-bottom: 3px solid var(--napari-color-text-base); +} + +.bd-header ul.navbar-nav li a.nav-link.dropdown-item { + color: var(--napari-color-text-base); + font-weight: 500; +} + +html .pst-navbar-icon, +html .pst-navbar-icon:hover { + color: var(--napari-color-text-base); +} + +/*************************** + version switcher +***************************/ + +button.btn.version-switcher__button { + padding-top: 0; + font-size: 0.875rem; + font-weight: 600; + border-style: none; + color: var(--napari-color-text-base); +} + +button.btn.version-switcher__button:hover { + color: var(--napari-color-text-base); +} + +.version-switcher__menu a.list-group-item { + background-color: var(--pst-color-background); + color: var(--napari-color-text-base); + padding: 0.5rem 0.5rem; + font-size: 0.875rem; +} + +.version-switcher__menu a.list-group-item:hover { + color: var(--napari-color-text-base); +} + +.version-switcher__menu, +button.version-switcher__button { + min-width: max-content; + border-radius: unset; +} + +/*************************** + sidebar +***************************/ + +/* Remove "Section Navigation" caption */ +.bd-links__title { + display: none; +} + +/* Move chevron to the left */ +.bd-sidebar-primary li.has-children > details > summary .toctree-toggle { + right: unset; +} + +/* Fonts and styles */ +.bd-sidebar a.reference, +.bd-sidebar .caption-text { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.bd-sidebar-primary .sidebar-primary-items__end { + margin-bottom: 0; + margin-top: 0; +} + +.bd-sidebar .toctree-l1 a { + padding-left: 32px; +} + +.bd-sidebar .toctree-l2 { + margin-left: -0.2rem; + border-left: 1px solid var(--napari-color-text-base); +} + +.bd-sidebar .toctree-l2 label { + left: 4px; +} + +.bd-sidebar .toctree-l2 a { + font-size: 0.875rem; + line-height: 1.5rem; + text-decoration-line: none; + border-left: 2px solid transparent; + color: var(--napari-color-text-base) !important; +} + +.bd-sidebar .toctree-l2 a:hover, +.bd-sidebar .toctree-l2 a.current:hover { + border-left: 2px solid var(--napari-primary-blue); +} + +.bd-sidebar .toctree-l2 a.current { + border-left: 2px solid var(--napari-color-text-base); +} + +.bd-sidebar .toctree-l3 label { + left: 6px; +} + +.bd-sidebar .toctree-l3 a { + font-size: 0.875rem; + line-height: 1.5rem; + text-decoration-line: none; + border-left: 2px solid transparent; + color: var(--napari-color-text-base) !important; + padding-left: 36px; +} + +.bd-sidebar .toctree-l3 a:hover, +.bd-sidebar .toctree-l3 a.current:hover { + border-left: 2px solid var(--napari-primary-blue); + margin-left: -1rem; + padding-left: 52px; +} + +.bd-sidebar .toctree-l3 a.current { + border-left: 2px solid var(--napari-color-text-base); + margin-left: -1rem; + padding-left: 52px; +} + +.bd-sidebar .toctree-l4 label { + left: 8px; +} + +.bd-sidebar .toctree-l4 a { + font-size: 0.875rem; + line-height: 1.5rem; + text-decoration-line: none; + border-left: 2px solid transparent; + color: var(--napari-color-text-base) !important; +} + +.bd-sidebar .toctree-l4 a:hover, +.bd-sidebar .toctree-l4 a.current:hover { + border-left: 2px solid var(--napari-primary-blue); + margin-left: -2rem; + padding-left: 68px; +} + +.bd-sidebar .toctree-l4 a.current { + border-left: 2px solid var(--napari-color-text-base); + margin-left: -2rem; + padding-left: 68px; +} + +.bd-sidebar .toctree-l5 label { + left: 10px; +} + +.bd-sidebar .toctree-l5 a { + font-size: 0.875rem; + line-height: 1.5rem; + text-decoration-line: none; + border-left: 2px solid transparent; + color: var(--napari-color-text-base) !important; +} + +.bd-sidebar .toctree-l5 a:hover, +.bd-sidebar .toctree-l5 a.current:hover { + border-left: 2px solid var(--napari-primary-blue); +} + +.bd-sidebar .toctree-l5 a.current { + border-left: 2px solid var(--napari-color-text-base); +} + +/* also related to navbar */ +.navbar-nav li a:focus, +.navbar-nav li a:hover, +.navbar-nav li.current > a { + color: var(--napari-color-text-base); +} + +nav.bd-links li > a { + color: var(--napari-color-text-base); + display: block; + line-height: 1.25rem; +} + +nav.bd-links li > a:active, +nav.bd-links li > a:hover { + color: var(--napari-color-text-base); +} + +nav.bd-links li > a:hover { + text-decoration: none !important; +} + +nav.bd-links .current > a { + box-shadow: none !important; +} + +/*************************** +search +***************************/ + +.bd-search { + border: 1px solid transparent; +} + +.bd-search:focus-within { + box-shadow: 0 0 0 0.1875rem var(--napari-primary-blue); +} + +.form-control { + border: 1px transparent; +} + +.form-control:focus, +.form-control:focus-visible { + background-color: var(--pst-color-background); + border: none; + box-shadow: none; + color: var(--pst-color-text-muted); + outline: none; +} + +/*************************** +page toc sidebar +***************************/ + +.onthispage { + border-style: none; + padding: 1px 0 5px; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 600; + text-transform: uppercase; + color: var(--napari-color-text-base) !important; + margin: 0 !important; +} + +.page-toc { + .section-nav { + padding-left: 0; + border-bottom: none; + } + + .onthispage { + color: var(--napari-color-text-base); + font-weight: var(--pst-sidebar-header-font-weight); + margin-bottom: 1rem; + } +} + +.toc-entry a.nav-link.active:hover { + color: var(--napari-color-text-base); +} + +.toc-entry a.nav-link:active, +.toc-entry a.nav-link:hover { + color: var(--napari-color-text-base); +} + +nav.page-toc { + border-left: 1px solid var(--napari-color-text-base); + padding-left: 1rem; +} + +.sidebar-secondary-item { + border-left: none !important; +} + +.toc-entry a.nav-link, +.toc-entry a > code { + color: var(--napari-color-text-base); +} + +.toc-entry > .nav-link { + border-left: 3px solid transparent; +} + +.toc-entry > .nav-link:hover { + border-left: 3px solid var(--napari-primary-blue); +} + +.toc-entry a.nav-link:hover { + text-decoration: none !important; +} + +.toc-entry a.nav-link.active { + box-shadow: none !important; + border-left: 3px solid var(--napari-color-text-base); +} + +.toc-h3.nav-item.toc-entry.active a { + margin-left: -2rem; + padding-left: 2rem; +} + +.toc-h3.nav-item.toc-entry a { + margin-left: -2rem; + padding-left: 2rem; +} + +.toc-h4.nav-item.toc-entry.active a { + margin-left: -3rem; + padding-left: 3rem; +} + +.toc-h4.nav-item.toc-entry a { + margin-left: -3rem; + padding-left: 3rem; +} + +.toc-h4.nav-item.toc-entry a:hover { + margin-left: -3rem; + padding-left: 3rem; +} + +/*************************** + napari calendar +***************************/ + +:root { + --fc-border-color: var(--napari-primary-blue); + --fc-daygrid-event-dot-width: 5px; + --fc-button-bg-color: var(--napari-primary-blue); + --fc-button-border-color: var(--napari-primary-blue); + --fc-button-text-color: var(--napari-color-text-base); + --fc-button-active-bg-color: var(--napari-deep-blue); + --fc-button-active-border-color: var(--napari-deep-blue); + --fc-button-hover-bg-color: var(--napari-deep-blue); + --fc-button-hover-border-color: var(--napari-deep-blue); + --fc-event-bg-color: var(--napari-light-blue); + --fc-event-border-color: var(--napari-light-blue); + --fc-event-text-color: var(--napari-color-text-base); +} + +.fc .fc-button:focus { + box-shadow: none; +} + +.fc-event-time { + margin-right: 3px; + min-width: fit-content; +} + +.fc-day-today .fc-daygrid-day-number { + background-color: var(--napari-primary-blue); +} + +.fc .fc-daygrid-day.fc-day-today { + background-color: unset; +} + +/*************************** + Admonitions +***************************/ + +.admonition, +div.admonition { + --color: #80d1ff; + border: var(--color) solid 1px !important; + border-radius: 0 !important; + box-shadow: none !important; + /*border-color: rgba(var(--pst-color-admonition-default), 1); */ + padding-left: 0 !important; + font-size: 0.938rem; + font-weight: 500; +} + +.admonition > .admonition-title, +div.admonition > .admonition-title { + text-transform: uppercase; + background: var(--color) !important; + font-size: 0.938rem !important; + font-weight: 700; +} + +/* Remove admonition title icon */ +div.admonition > .admonition-title:after, +.admonition > .admonition-title:after { + display: none; +} + +/* Padding and spacing */ +div.admonition.warning > ul.simple { + padding: 1.1rem !important; +} + +div.admonition > p, +div.admonition > ul.simple p { + font-size: 0.938rem; +} + +div.admonition > p { + padding-top: 0.5rem; + padding-bottom: 0.4rem; +} + +/* Toggle button */ +.admonition.toggle-hidden { + height: 40px; +} + +.admonition .toggle-button { + top: 0; + right: 0; + z-index: 10; + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + float: unset; +} + +.admonition .toggle-button::before { + display: none; +} + +.admonition .toggle-button svg { + transition-property: transform; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + transform: rotate(45deg); +} + +.admonition .toggle-button.toggle-button-hidden svg { + transform: rotate(0); +} + +/* Attention */ + +.admonition.attention { + --color: #d8f97d; +} + +/* Caution */ + +.admonition.caution { + --color: #ffc580; +} + +/* Warning */ + +.admonition.warning { + --color: #ffa680; +} + +/* Danger */ + +.admonition.danger { + --color: #ff8080; +} + +/* Error */ + +.admonition.error { + --color: #fade7d; +} + +/* Hint */ + +.admonition.hint { + --color: #8094ff; +} + +/* Tip */ + +.admonition.tip { + --color: #cf80ff; +} + +/* Important */ + +.admonition.important { + --color: #f1f379; +} + +/* Note */ + +.admonition.note { + --color: #80ffe0; +} + +/*************************** + Page container +***************************/ + +#pst-back-to-top { + background-color: var(--napari-light-blue); + color: var(--napari-dark-gray); +} + +/*************************** + Calendar popup +***************************/ + +/* The Modal (background) */ +.modal { + /* Hidden by default */ + position: fixed; + /* Stay in place */ + z-index: 1; + /* Sit on top */ + padding-top: 100px; + /* Location of the box */ + left: 0; + top: 0; + width: 100%; + /* Full width */ + height: 100%; + /* Full height */ + overflow: auto; + /* Enable scroll if needed */ + background-color: rgb(0, 0, 0); + /* Fallback color */ + background-color: rgba(0, 0, 0, 0.4); + /* Black w/ opacity */ +} + +/* Modal Content */ +.modal-content { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: #fefefe; + margin: auto; + padding: 0; + border: 1px solid #888; + box-shadow: + 0 4px 8px 0 rgba(0, 0, 0, 0.2), + 0 6px 20px 0 rgba(0, 0, 0, 0.19); +} + +/* Modal Content */ +.modal-content { + width: 30%; +} + +@media (max-width: 780px) { + .modal-content { + width: 50%; + } +} + +@media (max-width: 495px) { + .modal-content { + width: 80%; + } +} + +/* Add Animation */ +@-webkit-keyframes animatetop { + from { + top: -300px; + opacity: 0; + } + + to { + top: 0; + opacity: 1; + } +} + +@keyframes animatetop { + from { + top: -300px; + opacity: 0; + } + + to { + top: 0; + opacity: 1; + } +} + +/* The Close Button */ +.close { + color: white; + float: right; + font-size: 28px; + font-weight: bold; + padding-right: 12px; + padding-top: 4px; +} + +.close:hover, +.close:focus { + color: #000; + text-decoration: none; + cursor: pointer; +} + +.modal-header { + padding: 0 0 0 12px; + background-color: var(--napari-primary-blue); + color: white; + display: block; +} + +.modal-header h3 { + margin-top: 1rem; +} + +.modal-body { + padding: 12px; +} diff --git a/docs/_static/napari-sphinx-theme.css b/docs/_static/napari-sphinx-theme.css deleted file mode 100644 index b9919ef7e..000000000 --- a/docs/_static/napari-sphinx-theme.css +++ /dev/null @@ -1,970 +0,0 @@ -/*************************** - napari custom colors -***************************/ -@import url("https://fonts.googleapis.com/css2?family=Barlow:wght@400;500;600;700&display=swap"); - -html { - --napari-primary-blue: #80d1ff; - --napari-deep-blue: #009bf2; - --napari-light-blue: #d2efff; - --napari-dark-gray: #686868; - --napari-gray: #f7f7f7; - --pst-font-family-base: "Barlow", var(--pst-font-family-base-system); - --pst-font-family-heading: "Barlow", var(--pst-font-family-base-system); - --pst-font-family-monospace: "JetBrains Mono", - var(--pst-font-family-monospace-system); - --pst-font-size-base: 16px; - --pst-color-headerlink: var(--napari-dark-gray); - --pst-color-headerlink-hover: var(--napari-deep-blue); - --pst-color-surface: var(--napari-gray) !important; -} - -html[data-theme="light"] { - --pst-color-primary: black; - --pst-color-secondary: var(--napari-primary-blue); - --pst-color-background: white; - --napari-color-text-base: black; - --pst-color-text-base: var(--napari-color-text-base); - --pst-color-link: black; - --pst-color-link-hover: black !important; - --pst-color-inline-code: black !important; - --pst-color-inline-code-links: black !important; - --pst-color-on-background: white; - --pst-color-text-muted: var(--napari-dark-gray); - --pst-color-border: var(--napari-gray); - --pst-color-target: var(--napari-gray); -} - -/* Dark theme is currently unset - design/accessibility assessment is needed here */ -html[data-theme="dark"] { - --pst-color-primary: black; - --pst-color-secondary: var(--napari-primary-blue); - --pst-color-background: white; - --napari-color-text-base: black; - --pst-color-text-base: var(--napari-color-text-base); - --pst-color-link: black; - --pst-color-link-hover: black !important; - --pst-color-inline-code: black !important; - --pst-color-inline-code-links: black !important; - --pst-color-on-background: white; - --pst-color-text-muted: var(--napari-dark-gray); - --pst-color-border: var(--napari-gray); - --pst-color-target: var(--napari-gray); - --pst-color-secondary-bg: #e0c7ff; - --pst-color-primary-text: white; -} - -body { - margin: 0; - font-family: - "Barlow", - -apple-system, - BlinkMacSystemFont, - "Segoe UI", - Roboto, - "Helvetica Neue", - Arial, - "Noto Sans", - "Liberation Sans", - sans-serif, - "Apple Color Emoji", - "Segoe UI Emoji", - "Segoe UI Symbol", - "Noto Color Emoji"; - text-align: left; -} - -p, -.line-block .line { - line-height: 1.5; - font-size: 1.0625rem; -} - -h1 { - font-size: 2.1875rem; - line-height: 125%; - font-weight: bolder; -} - -/*************************** - napari footer -***************************/ - -.napari-footer { - display: flex; - flex-shrink: 0; - flex-direction: row; - flex-wrap: wrap; - width: 100%; - align-items: center; - justify-content: space-between; - background-color: black; - padding-top: 1.5rem; - padding-bottom: 0.5rem; - margin-top: 75px; -} - -@media (min-width: 495px) { - .napari-footer { - padding-left: 3rem; - padding-right: 3rem; - } - - .napari-footer a > span { - font-size: 0.875rem; - line-height: 1.25rem; - } -} - -.napari-footer p { - color: white; -} - -.napari-footer a { - white-space: nowrap; - text-decoration-line: none; - margin-right: 1rem; - margin-bottom: 1rem; - color: white !important; - display: flex; - flex-direction: row; - align-items: center; -} - -.napari-footer a:hover { - color: white; -} - -.napari-footer a:last-child { - margin-right: 0px; -} - -.napari-footer a > svg { - margin-right: 0.25rem; - display: inline-block; - height: 1em; - width: 1em; -} - -.napari-footer .footer-item { - display: flex; - flex-wrap: wrap; - align-items: center; -} - -.napari-footer .footer-item { - display: flex; - flex-wrap: wrap; - align-items: center; -} - -.napari-footer .footer-item--with-napari-copyright { - width: 100%; - justify-content: flex-end; -} - -.napari-footer .napari-copyright { - display: flex; - flex-direction: column; -} - -.napari-footer .napari-copyright, -.napari-footer .napari-copyright .copyright { - font-weight: 600; - font-size: 0.5625rem; - margin-bottom: auto; -} - -@media (min-width: 780px) { - .napari-footer .footer-item--with-napari-copyright { - width: max-content; - } - - .napari-footer .footer-item--with-napari-copyright { - justify-content: flex-start; - } -} - -@media (min-width: 495px) { - .napari-footer .napari-copyright, - .napari-footer .napari-copyright .copyright { - font-size: 0.875rem; - line-height: 1.25rem; - } -} - -.napari-footer .napari-copyright .sphinx-link, -.napari-footer .napari-copyright .sphinx-version { - display: flex; - justify-content: flex-start; -} - -.napari-footer - .napari-copyright - .sphinx-link - > :not([hidden]) - ~ :not([hidden]) { - margin-right: calc(0.25rem); - margin-left: calc(0.25rem); -} - -.napari-footer .napari-copyright .sphinx-version { - color: white; -} - -.napari-footer .footer-icon__hover-blue .footer-icon__light-blue { - display: none; -} - -.napari-footer .footer-icon__hover-blue:hover .footer-icon__regular { - display: none; -} - -.napari-footer .footer-icon__hover-blue:hover .footer-icon__light-blue { - display: block; -} - -/* Recommended by PST */ -.footer-items__start, -.footer-items__end { - flex-direction: row; -} - -.bd-footer__inner { - display: flex; - flex-shrink: 0; - flex-direction: row; - flex-wrap: wrap; - width: 100%; - max-width: 100%; - align-items: center; - justify-content: space-between; - background-color: black; -} - -/**************************** - Nav bar section -*****************************/ - -.navbar { - background-color: var(--napari-primary-blue) !important; - box-shadow: none; -} - -.navbar-brand { - vertical-align: middle; - font-size: 1.25rem; - color: black !important; - position: relative; - font-weight: bolder; -} -.navbar-brand:hover, -.navbar-brand:focus { - text-decoration: none !important; - color: var(--napari-color-text-base) !important; -} - -/* Navbar text */ -.bd-header ul.navbar-nav > li.nav-item > .nav-link { - color: var(--napari-color-text-base); - font-size: 1.0625rem; - font-weight: 500 !important; - border-bottom: 3px solid transparent; - padding: 16px 1.0625rem 16px !important; -} - -.bd-header ul.navbar-nav > li.nav-item > .nav-link:hover { - color: var(--napari-color-text-base); - font-size: 1.0625rem; - font-weight: 500 !important; - border-bottom: 3px solid var(--napari-color-text-base); -} - -.bd-header ul.navbar-nav > li.nav-item.current > .nav-link::before { - border-bottom: 0px solid var(--napari-color-text-base); -} - -.bd-header ul.navbar-nav > li.nav-item.current > .nav-link { - border-bottom: 3px solid var(--napari-color-text-base); - font-weight: 700 !important; -} - -.bd-header ul.navbar-nav { - height: var(--pst-header-height); -} - -.bd-header ul.navbar-nav > li.nav-item { - margin-inline: 0px; -} - -.bd-header ul.navbar-nav > li.nav-item.dropdown > .dropdown-toggle { - color: var(--napari-color-text-base); - font-size: 1.0625rem; - font-weight: 500 !important; - border-bottom: 3px solid transparent; - padding: 16px 1.0625rem 16px !important; - height: var(--pst-header-height); -} - -.bd-header ul.navbar-nav > li.nav-item.dropdown > .dropdown-toggle:hover { - box-shadow: none; - text-decoration: none; - border-bottom: 3px solid var(--napari-color-text-base); -} - -.bd-header ul.navbar-nav li a.nav-link.dropdown-item { - color: var(--napari-color-text-base); - font-weight: 500; -} - -html .pst-navbar-icon, -html .pst-navbar-icon:hover { - color: var(--napari-color-text-base); -} - -/*************************** - version switcher -***************************/ - -button.btn.version-switcher__button { - padding-top: 0px; - font-size: 0.875rem; - font-weight: 600; - border-style: none; - color: var(--napari-color-text-base); -} - -button.btn.version-switcher__button:hover { - color: var(--napari-color-text-base); -} - -.version-switcher__menu a.list-group-item { - background-color: var(--pst-color-background); - color: var(--napari-color-text-base); - padding: 0.5rem 0.5rem; - padding-top: 0.5rem; - padding-bottom: 0.5rem; - font-size: 0.875rem; -} - -.version-switcher__menu a.list-group-item:hover { - color: var(--napari-color-text-base); -} - -.version-switcher__menu, -button.version-switcher__button { - min-width: max-content; - border-radius: unset; -} - -/*************************** - sidebar -***************************/ - -/* Remove "Section Navigation" caption */ -.bd-links__title { - display: none; -} - -/* Move chevron to the left */ -.bd-sidebar-primary li.has-children > details > summary .toctree-toggle { - right: unset; -} - -/* Fonts and styles */ -.bd-sidebar a.reference, -.bd-sidebar .caption-text { - font-size: 0.875rem; - line-height: 1.25rem; -} - -.bd-sidebar-primary .sidebar-primary-items__end { - margin-bottom: 0; - margin-top: 0; -} - -.bd-sidebar .toctree-l1 a { - padding-left: 32px; -} - -.bd-sidebar .toctree-l2 { - margin-left: -0.2rem; - border-left: 1px solid var(--napari-color-text-base); -} - -.bd-sidebar .toctree-l2 label { - left: 4px; -} - -.bd-sidebar .toctree-l2 a { - font-size: 0.875rem; - line-height: 1.5rem; - text-decoration-line: none; - border-left: 2px solid transparent; - color: var(--napari-color-text-base) !important; -} - -.bd-sidebar .toctree-l2 a:hover, -.bd-sidebar .toctree-l2 a.current:hover { - border-left: 2px solid var(--napari-primary-blue); -} - -.bd-sidebar .toctree-l2 a.current { - border-left: 2px solid var(--napari-color-text-base); -} - -.bd-sidebar .toctree-l3 label { - left: 6px; -} - -.bd-sidebar .toctree-l3 a { - font-size: 0.875rem; - line-height: 1.5rem; - text-decoration-line: none; - border-left: 2px solid transparent; - color: var(--napari-color-text-base) !important; - padding-left: 36px; -} - -.bd-sidebar .toctree-l3 a:hover, -.bd-sidebar .toctree-l3 a.current:hover { - border-left: 2px solid var(--napari-primary-blue); - margin-left: -1rem; - padding-left: 52px; -} - -.bd-sidebar .toctree-l3 a.current { - border-left: 2px solid var(--napari-color-text-base); - margin-left: -1rem; - padding-left: 52px; -} - -.bd-sidebar .toctree-l4 label { - left: 8px; -} - -.bd-sidebar .toctree-l4 a { - font-size: 0.875rem; - line-height: 1.5rem; - text-decoration-line: none; - border-left: 2px solid transparent; - color: var(--napari-color-text-base) !important; -} - -.bd-sidebar .toctree-l4 a:hover, -.bd-sidebar .toctree-l4 a.current:hover { - border-left: 2px solid var(--napari-primary-blue); - margin-left: -2rem; - padding-left: 68px; -} - -.bd-sidebar .toctree-l4 a.current { - border-left: 2px solid var(--napari-color-text-base); - margin-left: -2rem; - padding-left: 68px; -} - -.bd-sidebar .toctree-l5 label { - left: 10px; -} - -.bd-sidebar .toctree-l5 a { - font-size: 0.875rem; - line-height: 1.5rem; - text-decoration-line: none; - border-left: 2px solid transparent; - color: var(--napari-color-text-base) !important; -} - -.bd-sidebar .toctree-l5 a:hover, -.bd-sidebar .toctree-l5 a.current:hover { - border-left: 2px solid var(--napari-primary-blue); -} - -.bd-sidebar .toctree-l5 a.current { - border-left: 2px solid var(--napari-color-text-base); -} - -.navbar-nav li a:focus, -.navbar-nav li a:hover, -.navbar-nav li.current > a { - color: var(--napari-color-text-base); -} - -nav.bd-links li > a { - color: var(--napari-color-text-base); - display: block; - line-height: 1.25rem; -} - -nav.bd-links li > a:active, -nav.bd-links li > a:hover { - color: var(--napari-color-text-base); -} - -nav.bd-links li > a:hover { - text-decoration: none !important; -} - -nav.bd-links .current > a { - box-shadow: none !important; -} - -/*************************** -search -***************************/ - -.bd-search { - border: 1px solid transparent; -} - -.bd-search:focus-within { - box-shadow: 0 0 0 0.1875rem var(--napari-primary-blue); -} - -.form-control { - border: 1px transparent; -} - -.form-control:focus, -.form-control:focus-visible { - background-color: var(--pst-color-background); - border: none; - box-shadow: none; - color: var(--pst-color-text-muted); - outline: none; -} - -/*************************** -page toc sidebar -***************************/ - -.onthispage { - border-style: none; - padding: 0px; - padding-top: 1px; - padding-bottom: 5px; - font-size: 0.875rem; - line-height: 1.25rem; - font-weight: 600; - text-transform: uppercase; - color: var(--napari-color-text-base) !important; - margin: 0 !important; -} - -.page-toc { - .section-nav { - padding-left: 0; - border-bottom: none; - } - - .onthispage { - color: var(--napari-color-text-base); - font-weight: var(--pst-sidebar-header-font-weight); - margin-bottom: 1rem; - } -} - -.toc-entry a.nav-link.active:hover { - color: var(--napari-color-text-base); -} - -.toc-entry a.nav-link:active, -.toc-entry a.nav-link:hover { - color: var(--napari-color-text-base); -} - -nav.page-toc { - border-left: 1px solid var(--napari-color-text-base); - padding-left: 1rem; -} - -.sidebar-secondary-item { - border-left: none !important; -} - -.toc-entry a.nav-link, -.toc-entry a > code { - color: var(--napari-color-text-base); -} - -.toc-entry > .nav-link { - border-left: 3px solid transparent; -} - -.toc-entry > .nav-link:hover { - border-left: 3px solid var(--napari-primary-blue); -} - -.toc-entry a.nav-link:hover { - text-decoration: none !important; -} - -.toc-entry a.nav-link.active { - box-shadow: none !important; - border-left: 3px solid var(--napari-color-text-base); -} - -.toc-h3.nav-item.toc-entry.active a { - margin-left: -2rem; - padding-left: 2rem; -} - -.toc-h3.nav-item.toc-entry a { - margin-left: -2rem; - padding-left: 2rem; -} - -.toc-h4.nav-item.toc-entry.active a { - margin-left: -3rem; - padding-left: 3rem; -} - -.toc-h4.nav-item.toc-entry a { - margin-left: -3rem; - padding-left: 3rem; -} - -.toc-h4.nav-item.toc-entry a:hover { - margin-left: -3rem; - padding-left: 3rem; -} - -/*************************** - napari calendar -***************************/ - -:root { - --fc-border-color: var(--napari-primary-blue); - --fc-daygrid-event-dot-width: 5px; - --fc-button-bg-color: var(--napari-primary-blue); - --fc-button-border-color: var(--napari-primary-blue); - --fc-button-text-color: var(--napari-color-text-base); - --fc-button-active-bg-color: var(--napari-deep-blue); - --fc-button-active-border-color: var(--napari-deep-blue); - --fc-button-hover-bg-color: var(--napari-deep-blue); - --fc-button-hover-border-color: var(--napari-deep-blue); - --fc-event-bg-color: var(--napari-light-blue); - --fc-event-border-color: var(--napari-light-blue); - --fc-event-text-color: var(--napari-color-text-base); -} - -.fc .fc-button:focus { - box-shadow: none; -} - -.fc-event-time { - margin-right: 3px; - min-width: fit-content; -} - -.fc-day-today .fc-daygrid-day-number { - background-color: var(--napari-primary-blue); -} - -.fc .fc-daygrid-day.fc-day-today { - background-color: unset; -} - -/*************************** - Textual elements -***************************/ - -h1 { - font-weight: 700; - color: var(--napari-color-text-base) !important; -} - -h2 { - font-weight: 700; - color: var(--napari-color-text-base) !important; -} - -h3 { - font-weight: 700; - color: var(--napari-color-text-base) !important; -} - -h4 { - font-weight: 700; - color: var(--napari-color-text-base) !important; -} - -h5 { - font-weight: 700; - color: var(--napari-color-text-base) !important; -} - -h6 { - font-weight: 700; - color: var(--napari-color-text-base) !important; -} - -a.headerlink { - color: var(--napari-dark-gray); -} - -.sd-card-hover:hover { - border-color: var(--napari-color-text-base) !important; - transform: scale(1.01); -} - -.prev-next-area p { - color: var(--napari-color-text-base); -} - -/*************************** - Admonitions -***************************/ - -.admonition, -div.admonition { - --color: #80d1ff; - border: var(--color) solid 1px !important; - border-radius: 0 !important; - box-shadow: none !important; - border-color: rgba(var(--pst-color-admonition-default), 1); - padding-left: 0 !important; - font-size: 0.938rem; - font-weight: 500; -} - -.admonition > .admonition-title, -div.admonition > .admonition-title { - text-transform: uppercase; - background: var(--color) !important; - font-size: 0.938rem !important; - font-weight: 700; -} - -/* Remove admonition title icon */ -div.admonition > .admonition-title:after, -.admonition > .admonition-title:after { - display: none; -} - -/* Padding and spacing */ -div.admonition.warning > ul.simple { - padding: 1.1rem !important; -} - -div.admonition > p, -div.admonition > ul.simple p { - font-size: 0.938rem; -} - -div.admonition > p { - padding-top: 0.5rem; - padding-bottom: 0.4rem; -} - -/* Toggle button */ -.admonition.toggle-hidden { - height: 40px; -} - -.admonition .toggle-button { - top: 0px; - right: 0px; - z-index: 10; - display: flex; - align-items: center; - justify-content: center; - width: 40px; - height: 40px; - float: unset; -} - -.admonition .toggle-button::before { - display: none; -} - -.admonition .toggle-button svg { - transition-property: transform; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; - transform: rotate(45deg); -} - -.admonition .toggle-button.toggle-button-hidden svg { - transform: rotate(0); -} - -/* Attention */ - -.admonition.attention { - --color: #d8f97d; -} - -/* Caution */ - -.admonition.caution { - --color: #ffc580; -} - -/* Warning */ - -.admonition.warning { - --color: #ffa680; -} - -/* Danger */ - -.admonition.danger { - --color: #ff8080; -} - -/* Error */ - -.admonition.error { - --color: #fade7d; -} - -/* Hint */ - -.admonition.hint { - --color: #8094ff; -} - -/* Tip */ - -.admonition.tip { - --color: #cf80ff; -} - -/* Important */ - -.admonition.important { - --color: #f1f379; -} - -/* Note */ - -.admonition.note { - --color: #80ffe0; -} - -/*************************** - Page container -***************************/ - -#pst-back-to-top { - background-color: var(--napari-light-blue); - color: var(--napari-dark-gray); -} - -/*************************** - Calendar popup -***************************/ - -/* The Modal (background) */ -.modal { - /* Hidden by default */ - position: fixed; - /* Stay in place */ - z-index: 1; - /* Sit on top */ - padding-top: 100px; - /* Location of the box */ - left: 0; - top: 0; - width: 100%; - /* Full width */ - height: 100%; - /* Full height */ - overflow: auto; - /* Enable scroll if needed */ - background-color: rgb(0, 0, 0); - /* Fallback color */ - background-color: rgba(0, 0, 0, 0.4); - /* Black w/ opacity */ -} - -/* Modal Content */ -.modal-content { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: #fefefe; - margin: auto; - padding: 0px; - border: 1px solid #888; - box-shadow: - 0 4px 8px 0 rgba(0, 0, 0, 0.2), - 0 6px 20px 0 rgba(0, 0, 0, 0.19); -} - -/* Modal Content */ -.modal-content { - width: 30%; -} - -@media (max-width: 780px) { - .modal-content { - width: 50%; - } -} - -@media (max-width: 495px) { - .modal-content { - width: 80%; - } -} - -/* Add Animation */ -@-webkit-keyframes animatetop { - from { - top: -300px; - opacity: 0; - } - - to { - top: 0; - opacity: 1; - } -} - -@keyframes animatetop { - from { - top: -300px; - opacity: 0; - } - - to { - top: 0; - opacity: 1; - } -} - -/* The Close Button */ -.close { - color: white; - float: right; - font-size: 28px; - font-weight: bold; - padding-right: 12px; - padding-top: 4px; -} - -.close:hover, -.close:focus { - color: #000; - text-decoration: none; - cursor: pointer; -} - -.modal-header { - padding: 0px 0px 0px 12px; - background-color: var(--napari-primary-blue); - color: white; - display: block; -} - -.modal-header h3 { - margin-top: 1rem; -} - -.modal-body { - padding: 12px; -} From ea84e400b332d81b7e438b0be5c32637da2b377b Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 10:09:43 -0800 Subject: [PATCH 08/21] move imports up, add search to navbar, navbar persistent to false --- docs/conf.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 5f1a429c4..c795711e6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,6 +16,7 @@ from jinja2.filters import FILTERS from packaging.version import parse as parse_version from pygments.lexers import TOMLLexer +from qtpy.QtWidgets import QApplication from sphinx_gallery import gen_rst from sphinx_gallery import scrapers from sphinx_gallery.sorting import ExampleTitleSortKey @@ -23,8 +24,10 @@ from sphinx.util import logging as sphinx_logging import napari +from napari.settings import get_settings from napari._version import __version_tuple__ + # -- Project information ----------------------------------------------------- project = "napari" @@ -96,12 +99,12 @@ ], "github_url": "https://github.com/napari/napari", "navbar_start": ["navbar-logo", "navbar-project"], - "navbar_end": ["version-switcher", "navbar-icon-links"], + "navbar_end": ["version-switcher", "navbar-icon-links", "search-field.html"], "switcher": { "json_url": json_url, "version_match": version_match, }, - "navbar_persistent": [], + "navbar_persistent": False, "header_links_before_dropdown": 6, "secondary_sidebar_items": ["page-toc"], "pygment_light_style": "napari", @@ -265,9 +268,6 @@ def get_supported_python_versions(project_name): def reset_napari(gallery_conf, fname): - from napari.settings import get_settings - from qtpy.QtWidgets import QApplication - settings = get_settings() settings.appearance.theme = "dark" From de8ace5a7b08aed69ee1bdecf4786142068a25cd Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 10:09:55 -0800 Subject: [PATCH 09/21] move imports up, add search to navbar, navbar persistent to false --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index c795711e6..5edf93efa 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -104,7 +104,7 @@ "json_url": json_url, "version_match": version_match, }, - "navbar_persistent": False, + "navbar_persistent": [], "header_links_before_dropdown": 6, "secondary_sidebar_items": ["page-toc"], "pygment_light_style": "napari", From 83955afc345ccdf12f9597a72587cf3e9197bb1a Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 10:18:05 -0800 Subject: [PATCH 10/21] remove search from navbar - too crowded --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 5edf93efa..01b9dc352 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -99,7 +99,7 @@ ], "github_url": "https://github.com/napari/napari", "navbar_start": ["navbar-logo", "navbar-project"], - "navbar_end": ["version-switcher", "navbar-icon-links", "search-field.html"], + "navbar_end": ["version-switcher", "navbar-icon-links"], "switcher": { "json_url": json_url, "version_match": version_match, From b29e3edd6fa71ff1ffb5552b9a907de14b0591ab Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 10:42:59 -0800 Subject: [PATCH 11/21] Add comment in css for footer, update conf --- docs/_static/custom.css | 2 +- docs/conf.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 3ac83927c..d4c258b44 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -337,7 +337,7 @@ a.headerlink { display: block; } -/* Recommended by PST */ +/* Recommended by PST so that components will display horizontally */ .footer-items__start, .footer-items__end { flex-direction: row; diff --git a/docs/conf.py b/docs/conf.py index 01b9dc352..5e0eecc44 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -98,15 +98,19 @@ }, ], "github_url": "https://github.com/napari/napari", + "navbar_align": "content", "navbar_start": ["navbar-logo", "navbar-project"], + "navbar_center": ["navbar-nav"], "navbar_end": ["version-switcher", "navbar-icon-links"], "switcher": { "json_url": json_url, "version_match": version_match, }, "navbar_persistent": [], + "navigation_with_keys": True, "header_links_before_dropdown": 6, - "secondary_sidebar_items": ["page-toc"], + "page_sidebar_items": ["page-toc.html"], + "secondary_sidebar_items": ["page-toc", "sourcelink"], "pygment_light_style": "napari", "pygment_dark_style": "napari", "announcement": "", From 8241533a0a63f60be6a4de64b33051a742c36c65 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 11:32:08 -0800 Subject: [PATCH 12/21] reorder conf.py and comment --- docs/conf.py | 257 +++++++++++++++++++++++++++++---------------------- 1 file changed, 144 insertions(+), 113 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 5e0eecc44..0e6f7d866 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,8 +1,9 @@ # Configuration file for the Sphinx documentation builder. # -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html +# For sphinx config settings available, see: +# See https://www.sphinx-doc.org/en/master/usage/configuration.html +# For theme specific config, see: +# https://pydata-sphinx-theme.readthedocs.io/en/stable/index.html import logging import os @@ -27,6 +28,7 @@ from napari.settings import get_settings from napari._version import __version_tuple__ +logger = logging.getLogger(__name__) # -- Project information ----------------------------------------------------- @@ -34,15 +36,9 @@ copyright = f"{datetime.now().year}, The napari team" author = "The napari team" -release = napari.__version__ -if "dev" in release: - version = "dev" -else: - version = release - # -- General configuration --------------------------------------------------- -# Add sphinx extensions here +# Add sphinx extensions here, as strings. extensions = [ "sphinx.ext.autodoc", "sphinx.ext.autosummary", @@ -59,25 +55,109 @@ "sphinxcontrib.mermaid", ] +# Config for sphinx.ext.autosummary + autosummary_generate = True autosummary_imported_members = True autosummary_ignore_module_all = False +# Config for sphinx_copybutton + +# Specify how to identify the prompt when copying code snippets +copybutton_prompt_text = r">>> |\.\.\. " +copybutton_prompt_is_regexp = True +copybutton_exclude = "style" + +# Config for sphinx_external_toc + external_toc_path = "_toc.yml" external_toc_exclude_missing = False +# Config for sphinx.ext.intersphinx + +intersphinx_mapping = { + "python": ["https://docs.python.org/3", None], + "numpy": ["https://numpy.org/doc/stable/", None], + # napari_plugin_engine is deprecated + "napari_plugin_engine": [ + "https://napari-plugin-engine.readthedocs.io/en/latest/", + "https://napari-plugin-engine.readthedocs.io/en/latest/objects.inv", + ], + "magicgui": [ + "https://pyapp-kit.github.io/magicgui/", + "https://pyapp-kit.github.io/magicgui/objects.inv", + ], + "app-model": [ + "http://app-model.readthedocs.io/en/latest/", + "http://app-model.readthedocs.io/en/latest/objects.inv", + ], + "vispy": [ + "https://vispy.org/", + "https://vispy.org/objects.inv", + ], +} + +# Config for sphinx_tags + tags_create_tags = True tags_output_dir = "_tags" tags_overview_title = "Tags" tags_extension = ["md", "rst"] +# Config for sphinxcontrib.mermaid + mermaid_d3_zoom = True mermaid_version = "11.4.1" mermaid_include_elk = "" -# -- Options for HTML output ------------------------------------------------- +# Config for myst_nb -html_theme = "pydata_sphinx_theme" +myst_enable_extensions = [ + "colon_fence", + "dollarmath", + "substitution", + "tasklist", + "attrs_inline", + "linkify", +] + +myst_heading_anchors = 4 + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [ + "_build", + "Thumbs.db", + ".DS_Store", + ".jupyter_cache", + "jupyter_execute", + "plugins/_*.md", + "plugins/building_a_plugin/_layer_data_guide.md", + "gallery/index.rst", +] + +myst_footnote_transition = False + +nb_output_stderr = "show" + +panels_add_bootstrap_css = False +pygments_style = "solarized-dark" +suppress_warnings = ["myst.header", "etoc.toctree", "config.cache"] + +napoleon_custom_sections = [("Events", "params_style")] +lexers["toml"] = TOMLLexer(startinline=True) + +# -- Config for versions ---------------------------------------------------- + +release = napari.__version__ +if "dev" in release: + version = "dev" +else: + version = release # Define the json_url for our version switcher. json_url = "https://napari.org/dev/_static/version_switcher.json" @@ -87,6 +167,48 @@ else: version_match = release + +def get_supported_python_versions(project_name): + """ + Get the supported Python versions for a given project + based on the classifiers in its distribution metadata. + """ + dist = distribution(project_name) + classifiers = [ + value + for key, value in dist.metadata.items() + if key == "Classifier" and value.startswith("Programming Language :: Python ::") + ] + return [ + parse_version(c.split(" :: ")[-1]) + for c in classifiers + if not c.endswith("Only") + ] + + +napari_supported_python_versions = get_supported_python_versions("napari") + +min_python_version = min(napari_supported_python_versions) +max_python_version = max(napari_supported_python_versions) + +version_string = ".".join(str(x) for x in __version_tuple__[:3]) +# when updating the version below, ensure to also update napari/napari README +python_version = "3.11" +python_version_range = f"{min_python_version}-{max_python_version}" + +myst_substitutions = { + "napari_conda_version": f"`napari={version_string}`", + "napari_version": version_string, + "python_version": python_version, + "python_version_range": python_version_range, + "python_version_code": f"`python={python_version}`", + "conda_create_env": f"```sh\nconda create -y -n napari-env -c conda-forge python={python_version}\nconda activate napari-env\n```", +} + +# -- Options for HTML output ------------------------------------------------- + +html_theme = "pydata_sphinx_theme" + html_theme_options = { "external_links": [ {"name": "napari hub", "url": "https://napari-hub.org"}, @@ -168,108 +290,8 @@ html_css_files = [ "custom.css", - "napari-sphinx-theme.css", -] - -intersphinx_mapping = { - "python": ["https://docs.python.org/3", None], - "numpy": ["https://numpy.org/doc/stable/", None], - # napari_plugin_engine is deprecated - "napari_plugin_engine": [ - "https://napari-plugin-engine.readthedocs.io/en/latest/", - "https://napari-plugin-engine.readthedocs.io/en/latest/objects.inv", - ], - "magicgui": [ - "https://pyapp-kit.github.io/magicgui/", - "https://pyapp-kit.github.io/magicgui/objects.inv", - ], - "app-model": [ - "http://app-model.readthedocs.io/en/latest/", - "http://app-model.readthedocs.io/en/latest/objects.inv", - ], - "vispy": [ - "https://vispy.org/", - "https://vispy.org/objects.inv", - ], -} - -myst_enable_extensions = [ - "colon_fence", - "dollarmath", - "substitution", - "tasklist", - "attrs_inline", - "linkify", -] - -myst_heading_anchors = 4 - - -def get_supported_python_versions(project_name): - """ - Get the supported Python versions for a given project - based on the classifiers in its distribution metadata. - """ - dist = distribution(project_name) - classifiers = [ - value - for key, value in dist.metadata.items() - if key == "Classifier" and value.startswith("Programming Language :: Python ::") - ] - return [ - parse_version(c.split(" :: ")[-1]) - for c in classifiers - if not c.endswith("Only") - ] - - -napari_supported_python_versions = get_supported_python_versions("napari") - -min_python_version = min(napari_supported_python_versions) -max_python_version = max(napari_supported_python_versions) - -version_string = ".".join(str(x) for x in __version_tuple__[:3]) -# when updating the version below, ensure to also update napari/napari README -python_version = "3.11" -python_version_range = f"{min_python_version}-{max_python_version}" - -myst_substitutions = { - "napari_conda_version": f"`napari={version_string}`", - "napari_version": version_string, - "python_version": python_version, - "python_version_range": python_version_range, - "python_version_code": f"`python={python_version}`", - "conda_create_env": f"```sh\nconda create -y -n napari-env -c conda-forge python={python_version}\nconda activate napari-env\n```", -} - -myst_footnote_transition = False - -nb_output_stderr = "show" - -panels_add_bootstrap_css = False -pygments_style = "solarized-dark" -suppress_warnings = ["myst.header", "etoc.toctree", "config.cache"] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [ - "_build", - "Thumbs.db", - ".DS_Store", - ".jupyter_cache", - "jupyter_execute", - "plugins/_*.md", - "plugins/building_a_plugin/_layer_data_guide.md", - "gallery/index.rst", ] -napoleon_custom_sections = [("Events", "params_style")] -lexers["toml"] = TOMLLexer(startinline=True) - def reset_napari(gallery_conf, fname): settings = get_settings() @@ -309,7 +331,7 @@ def napari_scraper(block, block_vars, gallery_conf): return scrapers.figure_rst(img_paths, gallery_conf["src_dir"]) -# -- Sphinx gallery +# -- Sphinx gallery ---------------------------------------------------- gen_rst.EXAMPLE_HEADER = """ .. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. @@ -353,6 +375,8 @@ def napari_scraper(block, block_vars, gallery_conf): "within_subsection_order": ExampleTitleSortKey, } +# -- Google calendar integration ---------------------------------------- + GOOGLE_CALENDAR_API_KEY = os.environ.get("GOOGLE_CALENDAR_API_KEY", "") @@ -426,6 +450,9 @@ def setup(app): warning_handler.filters.insert(0, FilterSphinxWarnings(app)) +# -- Attributes for autosummary -------------------------------------- + + def get_attributes(item, obj, modulename): """Filters attributes to be used in autosummary. @@ -444,6 +471,8 @@ def get_attributes(item, obj, modulename): FILTERS["get_attributes"] = get_attributes +# -- Config for linkcheck --------------------------------------------------- + linkcheck_anchors_ignore = [r"^!", r"L\d+-L\d+", r"r\d+", r"issuecomment-\d+"] linkcheck_ignore = [ "https://napari.zulipchat.com/", @@ -463,6 +492,8 @@ def get_attributes(item, obj, modulename): r"https://github\.com/napari/napari/releases/download/.*": r"https://objects\.githubusercontent\.com/.*", } +# -- GitHub Anchors for Links ----------------------------------------- + def rewrite_github_anchor(app, uri: str): """Rewrite anchor name of the hyperlink to github.com From 9d382816dd58badce10f4130f82b011023ee6537 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 13:32:28 -0800 Subject: [PATCH 13/21] update deprecated pygments --- docs/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 0e6f7d866..710ef5786 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -233,8 +233,8 @@ def get_supported_python_versions(project_name): "header_links_before_dropdown": 6, "page_sidebar_items": ["page-toc.html"], "secondary_sidebar_items": ["page-toc", "sourcelink"], - "pygment_light_style": "napari", - "pygment_dark_style": "napari", + "pygments_light_style": "napari", + "pygments_dark_style": "napari", "announcement": "", "back_to_top_button": False, "analytics": { From 6b886517185b072a4ab52274101d58a341b81a27 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 13:33:11 -0800 Subject: [PATCH 14/21] remove napari theme from requirements --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 515edfd9f..322b3170b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -sphinx<8 # break build docs because of warnings +sphinx<8 # break build docs because of warnings sphinx-autobuild sphinx-tabs sphinx-tags @@ -10,7 +10,7 @@ sphinx-gallery sphinx_autodoc_typehints==1.12.0 sphinxcontrib-mermaid>=1.0.0 myst-nb -napari-sphinx-theme>=0.3.0 +pydata-sphinx-theme matplotlib lxml_html_clean imageio-ffmpeg From 18c71a6fd0ad11546e333db5a970e960dfc71fe5 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 13:35:05 -0800 Subject: [PATCH 15/21] exclude refactor tracking doc --- docs/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/conf.py b/docs/conf.py index 710ef5786..09cd24995 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -138,6 +138,7 @@ "plugins/_*.md", "plugins/building_a_plugin/_layer_data_guide.md", "gallery/index.rst", + "refactor.md", ] myst_footnote_transition = False From fc7ede275dfe1d37f5104cdd961c5e84edc0e889 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 13:36:37 -0800 Subject: [PATCH 16/21] remove pages sidebar config --- docs/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 09cd24995..7e0a8bb23 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -232,7 +232,6 @@ def get_supported_python_versions(project_name): "navbar_persistent": [], "navigation_with_keys": True, "header_links_before_dropdown": 6, - "page_sidebar_items": ["page-toc.html"], "secondary_sidebar_items": ["page-toc", "sourcelink"], "pygments_light_style": "napari", "pygments_dark_style": "napari", From d0cef1f364e7f27ade48507041a420fca0646874 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 13:39:26 -0800 Subject: [PATCH 17/21] add refactor doc --- docs/refactor.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 docs/refactor.md diff --git a/docs/refactor.md b/docs/refactor.md new file mode 100644 index 000000000..b118fea33 --- /dev/null +++ b/docs/refactor.md @@ -0,0 +1,14 @@ +# Refactor custom theme to pydata theme plus config + +## Motivation + +- Maintaining a separate theme adds more burden. +- Adding more complexity than needed. +- Frustrating to contribute since builds aren't clear to do locally. + +## TODO + +- reduce warnings +- add scripts from nap theme here maybe +- pygments highlighting +- From 39a6df5a664848bcc5bbd8c6c18a3b86be166afb Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 14:08:21 -0800 Subject: [PATCH 18/21] add logging to scripts for debug --- docs/_scripts/prep_docs.py | 28 ++++++++++++++++-------- docs/_scripts/update_event_docs.py | 4 +++- docs/_scripts/update_preference_docs.py | 7 ++++-- docs/_scripts/update_ui_sections_docs.py | 26 ++++++++++++---------- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/docs/_scripts/prep_docs.py b/docs/_scripts/prep_docs.py index ce110388c..1223276c3 100644 --- a/docs/_scripts/prep_docs.py +++ b/docs/_scripts/prep_docs.py @@ -6,17 +6,26 @@ from which this script will be called. """ +import logging import sys from importlib.metadata import version from pathlib import Path from packaging.version import parse + +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) +handler = logging.StreamHandler(sys.stdout) +formatter = logging.Formatter("[%(levelname)s] - %(asctime)s - %(name)s - %(message)s") +handler.setFormatter(formatter) +logger.addHandler(handler) + # Set up paths to docs and npe2 docs source DOCS = Path(__file__).parent.parent.absolute() -print(DOCS) +logger.debug(f"DOCS: {DOCS}") NPE = DOCS.parent.absolute() / "npe2" -print(NPE) +logger.debug(f"NPE: {NPE}") def prep_npe2(): @@ -25,17 +34,17 @@ def prep_npe2(): Some plugin-related docs live in the npe2 repo to simplify plugin testing. """ - print("Entered prep_npe2") + logger.debug("Preparing npe2 plugin") # Checks if the path to npe2 repo exist. If so, bail. if NPE.exists(): - print("npe2 is already installed. moving on") + logger.debug("NPE2 plugin already present") return from subprocess import check_call npe2_version = version("npe2") - print(f"npe2 version: {npe2_version}") + logger.debug(f"npe2 version: {npe2_version}") check_call(f"rm -rf {NPE}".split()) - print("removing NPE directory succeeded") + logger.debug("removing NPE directory succeeded") check_call(f"git clone https://github.com/napari/npe2 {NPE}".split()) if not parse(npe2_version).is_devrelease: @@ -47,12 +56,13 @@ def prep_npe2(): def main(): prep_npe2() + logger.debug("Prep npe2 complete") __import__("update_preference_docs").main() - print("update_preference_docs succeeded") + logger.debug("update_preference_docs succeeded") __import__("update_event_docs").main() - print("update_event_docs succeeded") + logger.debug("update_event_docs succeeded") __import__("update_ui_sections_docs").main() - print("update_ui_sections_docs succeeded") + logger.debug("update_ui_sections_docs succeeded") if __name__ == "__main__": diff --git a/docs/_scripts/update_event_docs.py b/docs/_scripts/update_event_docs.py index 71254fd78..183b32723 100644 --- a/docs/_scripts/update_event_docs.py +++ b/docs/_scripts/update_event_docs.py @@ -1,5 +1,6 @@ import ast import inspect +import logging from dataclasses import dataclass from pathlib import Path from types import ModuleType @@ -15,7 +16,8 @@ from napari.components.viewer_model import ViewerModel from napari.utils.events import EventedModel -print("imports in update_event_docs succeeded") +logger = logging.getLogger(__name__) + DOCS = Path(__file__).parent.parent diff --git a/docs/_scripts/update_preference_docs.py b/docs/_scripts/update_preference_docs.py index 5c621b58f..956d32695 100644 --- a/docs/_scripts/update_preference_docs.py +++ b/docs/_scripts/update_preference_docs.py @@ -1,3 +1,4 @@ +import logging from pathlib import Path from jinja2 import Template @@ -10,6 +11,8 @@ from napari._pydantic_compat import ModelMetaclass from napari.settings import NapariSettings +logger = logging.getLogger(__name__) + DOCS = REPO_ROOT_PATH = Path(__file__).resolve().parent.parent GUIDES_PATH = DOCS / "guides" IMAGES_PATH = DOCS / "images" / "_autogenerated" @@ -170,9 +173,9 @@ def create_preferences_docs(): def main(): - print("start generate image") + logger.debug("begin generating images") generate_images() - print("generate preferences docs") + logger.debug("create preferences docs") create_preferences_docs() diff --git a/docs/_scripts/update_ui_sections_docs.py b/docs/_scripts/update_ui_sections_docs.py index 0ac5a3206..26c2e3d0a 100644 --- a/docs/_scripts/update_ui_sections_docs.py +++ b/docs/_scripts/update_ui_sections_docs.py @@ -1,5 +1,6 @@ # ---- Standard library imports import json +import logging from pathlib import Path # ---- Third-party imports @@ -17,6 +18,7 @@ from napari._qt.widgets import qt_viewer_status_bar from napari_console import qt_console +logger = logging.getLogger(__name__) # ---- General constants # Docs paths @@ -33,7 +35,7 @@ DIALOGS_MODULE_PATH = Path(dialogs.__file__).parent CONSOLE_MODULE_PATH = Path(qt_console.__file__).parent -print("set paths in update ui sections") +logger.debug("paths successfully set in update ui sections") # ---- Utility functions @@ -376,7 +378,7 @@ def generate_docs_ui_section( # ---- Main and UI sections parameters def main(): - print("ui sections created") + logger.debug("Empty ui sections list created") ui_sections = [] # --- mermaid settings @@ -424,7 +426,7 @@ def main(): "--no-output", ] - print("adding layer list to ui section") + logger.debug("adding layer list to ui section") ui_sections.append( ( layer_list_section_name, @@ -435,7 +437,7 @@ def main(): ) # ---- Layer controls section parameters - print("start layer controls") + logger.debug("start layer controls") layer_controls_section_name = "Layers controls" layer_controls_output_page = UI_SECTIONS_DOCS_ROOT_PATH / "layers_controls_ui.md" layer_controls_pydeps_args = [ @@ -467,7 +469,7 @@ def main(): "--no-output", ] - print("adding layer controls to ui section") + logger.debug("adding layer controls to ui section") ui_sections.append( ( layer_controls_section_name, @@ -507,7 +509,7 @@ def main(): "--show-deps", "--no-output", ] - print("adding application status bar to ui section") + logger.debug("adding application status bar to ui section") ui_sections.append( ( application_status_bar_section_name, @@ -559,7 +561,7 @@ def main(): "--show-deps", "--no-output", ] - print("adding application menus to ui section") + logger.debug("adding application menus to ui section") ui_sections.append( ( application_menus_section_name, @@ -601,7 +603,7 @@ def main(): "--show-deps", "--no-output", ] - print("adding viewer to ui section") + logger.debug("adding viewer to ui section") ui_sections.append( ( viewer_section_name, @@ -656,7 +658,7 @@ def main(): "--show-deps", "--no-output", ] - print("adding dialogs to ui section") + logger.debug("adding dialogs to ui section") ui_sections.append( ( dialogs_section_name, @@ -684,7 +686,7 @@ def main(): "--show-deps", "--no-output", ] - print("adding console to ui section") + logger.debug("adding console to ui section") ui_sections.append( ( console_section_name, @@ -694,8 +696,8 @@ def main(): ) ) - print("getting ready to iterate over sections") - print(f"ui sections {ui_sections}") + logger.debug("getting ready to iterate over sections") + logger.debug(f"ui sections {ui_sections}") for ( section_name, output_page, From 3ab93eb3778e50eba2b8c38d6170d25f24f05499 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 14:43:40 -0800 Subject: [PATCH 19/21] more logging --- docs/_scripts/prep_docs.py | 15 +++--- docs/_scripts/scripts_logger.py | 59 ++++++++++++++++++++++++ docs/_scripts/update_event_docs.py | 18 +++++++- docs/_scripts/update_preference_docs.py | 16 +++++-- docs/_scripts/update_ui_sections_docs.py | 11 ++++- 5 files changed, 103 insertions(+), 16 deletions(-) create mode 100644 docs/_scripts/scripts_logger.py diff --git a/docs/_scripts/prep_docs.py b/docs/_scripts/prep_docs.py index 1223276c3..bc502f407 100644 --- a/docs/_scripts/prep_docs.py +++ b/docs/_scripts/prep_docs.py @@ -6,20 +6,16 @@ from which this script will be called. """ -import logging +import os import sys from importlib.metadata import version from pathlib import Path from packaging.version import parse +from scripts_logger import setup_logger -logger = logging.getLogger(__name__) -logger.setLevel(logging.DEBUG) -handler = logging.StreamHandler(sys.stdout) -formatter = logging.Formatter("[%(levelname)s] - %(asctime)s - %(name)s - %(message)s") -handler.setFormatter(formatter) -logger.addHandler(handler) +logger = setup_logger(__name__) # Set up paths to docs and npe2 docs source DOCS = Path(__file__).parent.parent.absolute() @@ -66,4 +62,9 @@ def main(): if __name__ == "__main__": + # Example usage within a script + current_script_name = os.path.basename(__file__) + # Get the name of the current script + logger = setup_logger(current_script_name) + main() diff --git a/docs/_scripts/scripts_logger.py b/docs/_scripts/scripts_logger.py new file mode 100644 index 000000000..8ba3a4923 --- /dev/null +++ b/docs/_scripts/scripts_logger.py @@ -0,0 +1,59 @@ +"""Create a logger for a directory of scripts to aid in debugging.""" + +import logging +import os +import sys + + +def setup_logger(script_name, log_directory="logs"): + """Sets up a logger for a specific script. + + Args: + script_name (str): The name of the script (e.g., "my_script.py"). + log_directory (str, optional): The directory to store log files. Defaults to "logs". + + Returns: + logging.Logger: A configured logger instance. + """ + # Create log directory if it doesn't exist + if not os.path.exists(log_directory): + os.makedirs(log_directory) + + # Extract the script name without the extension + script_name_no_ext = os.path.splitext(script_name)[0] + + # Create a logger + logger = logging.getLogger(script_name_no_ext) + logger.setLevel(logging.DEBUG) # Set the minimum logging level + + # Create a file handler + # log_file_path = os.path.join(log_directory, f"{script_name_no_ext}.log") + # file_handler = logging.FileHandler(log_file_path) + # file_handler.setLevel(logging.DEBUG) + + handler = logging.StreamHandler(sys.stdout) + + # Create a formatter + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + ) + # file_handler.setFormatter(formatter) + handler.setFormatter(formatter) + + # Add the file handler to the logger + # logger.addHandler(file_handler) + logger.addHandler(handler) + return logger + + +if __name__ == "__main__": + # Example usage within a script + current_script_name = os.path.basename(__file__) + # Get the name of the current script + logger = setup_logger(current_script_name) + + logger.debug("This is a debug message.") + logger.info("This is an info message.") + logger.warning("This is a warning message.") + logger.error("This is an error message.") + logger.critical("This is a critical message.") diff --git a/docs/_scripts/update_event_docs.py b/docs/_scripts/update_event_docs.py index 183b32723..5e1f40b15 100644 --- a/docs/_scripts/update_event_docs.py +++ b/docs/_scripts/update_event_docs.py @@ -1,6 +1,6 @@ import ast import inspect -import logging +import os from dataclasses import dataclass from pathlib import Path from types import ModuleType @@ -16,7 +16,9 @@ from napari.components.viewer_model import ViewerModel from napari.utils.events import EventedModel -logger = logging.getLogger(__name__) +from scripts_logger import setup_logger + +logger = setup_logger(__name__) DOCS = Path(__file__).parent.parent @@ -74,6 +76,7 @@ def walk_modules( module: ModuleType, pkg="napari", _walked=None ) -> Iterator[ModuleType]: """walk all modules in pkg, starting with `module`.""" + logger.debug(f"walking {pkg}") if not _walked: _walked = set() yield module @@ -90,6 +93,7 @@ def walk_modules( def iter_classes(module: ModuleType) -> Iterator[Type]: """iter all classes in module""" + logger.debug(f"walking {module}") for name in dir(module): attr = getattr(module, name) if inspect.isclass(attr) and attr.__module__ == module.__name__: @@ -97,12 +101,14 @@ def iter_classes(module: ModuleType) -> Iterator[Type]: def class_doc_attrs(kls: Type) -> Dict[str, Parameter]: + logger.debug(f"walking {kls}") docs = {p.name: " ".join(p.desc) for p in ClassDoc(kls).get("Attributes")} docs.update({p.name: " ".join(p.desc) for p in ClassDoc(kls).get("Parameters")}) return docs def iter_evented_model_events(module: ModuleType = napari) -> Iterator[Ev]: + logger.debug(f"walking evented model events {module}") for mod in walk_modules(module): for kls in iter_classes(mod): if not issubclass(kls, EventedModel): @@ -118,6 +124,7 @@ def iter_evented_model_events(module: ModuleType = napari) -> Iterator[Ev]: def iter_evented_container_events( module: ModuleType = napari, container_class=LayerList ) -> Iterator[Ev]: + logger.debug(f"walking evented container events {module}") for mod in walk_modules(module): for kls in iter_classes(mod): if not issubclass(kls, container_class): @@ -149,6 +156,7 @@ def visit_Call(self, node: ast.Call): def base_event_names() -> List[str]: + logger.debug("walking base event names") from napari.layers.base import base root = ast.parse(Path(base.__file__).read_text()) @@ -158,6 +166,7 @@ def base_event_names() -> List[str]: def iter_layer_events() -> Iterator[Ev]: + logger.debug("walking layer events") basenames = base_event_names() docs = class_doc_attrs(layers.Layer) for name in basenames: @@ -191,6 +200,7 @@ def iter_layer_events() -> Iterator[Ev]: def merge_image_and_label_rows(rows: List[List[str]]): """Merge events common to _ImageBase or IntensityVisualizationMixin.""" + logger.debug(f"merging {len(rows)} rows") # find events that are common across both Image, Labels and Surface layers. image_events = {r[1] for r in rows if r[0] == "`Image`"} labels_events = {r[1] for r in rows if r[0] == "`Labels`"} @@ -264,4 +274,8 @@ def main(): if __name__ == "__main__": + # Example usage within a script + current_script_name = os.path.basename(__file__) + # Get the name of the current script + logger = setup_logger(current_script_name) main() diff --git a/docs/_scripts/update_preference_docs.py b/docs/_scripts/update_preference_docs.py index 956d32695..5c15c16a5 100644 --- a/docs/_scripts/update_preference_docs.py +++ b/docs/_scripts/update_preference_docs.py @@ -1,4 +1,4 @@ -import logging +import os from pathlib import Path from jinja2 import Template @@ -11,7 +11,9 @@ from napari._pydantic_compat import ModelMetaclass from napari.settings import NapariSettings -logger = logging.getLogger(__name__) +from scripts_logger import setup_logger + +logger = setup_logger(__name__) DOCS = REPO_ROOT_PATH = Path(__file__).resolve().parent.parent GUIDES_PATH = DOCS / "guides" @@ -101,7 +103,7 @@ def generate_images(): Generate images from `CORE_SETTINGS`. and save them in the developer section of the docs. """ - + logger.debug("Generating images") app = get_qapp() pref = PreferencesDialog() pref.setStyleSheet(get_stylesheet("dark")) @@ -134,6 +136,7 @@ def grab(): def create_preferences_docs(): """Create preferences docs from SETTINGS using a jinja template.""" + logger.debug("Creating preferences docs") sections = {} for name, field in NapariSettings.__fields__.items(): @@ -173,11 +176,14 @@ def create_preferences_docs(): def main(): - logger.debug("begin generating images") generate_images() - logger.debug("create preferences docs") create_preferences_docs() if __name__ == "__main__": + # Example usage within a script + current_script_name = os.path.basename(__file__) + # Get the name of the current script + logger = setup_logger(current_script_name) + main() diff --git a/docs/_scripts/update_ui_sections_docs.py b/docs/_scripts/update_ui_sections_docs.py index 26c2e3d0a..a5ab07246 100644 --- a/docs/_scripts/update_ui_sections_docs.py +++ b/docs/_scripts/update_ui_sections_docs.py @@ -1,6 +1,6 @@ # ---- Standard library imports import json -import logging +import os from pathlib import Path # ---- Third-party imports @@ -18,7 +18,9 @@ from napari._qt.widgets import qt_viewer_status_bar from napari_console import qt_console -logger = logging.getLogger(__name__) +from scripts_logger import setup_logger + +logger = setup_logger(__name__) # ---- General constants # Docs paths @@ -713,4 +715,9 @@ def main(): if __name__ == "__main__": + # Example usage within a script + current_script_name = os.path.basename(__file__) + # Get the name of the current script + logger = setup_logger(current_script_name) + main() From fe599a9d75a676c0ec744bd8b6cf0c14bdd4854b Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 14:58:49 -0800 Subject: [PATCH 20/21] add refactor doc --- docs/refactor.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/refactor.md b/docs/refactor.md index b118fea33..8e33d0008 100644 --- a/docs/refactor.md +++ b/docs/refactor.md @@ -6,9 +6,12 @@ - Adding more complexity than needed. - Frustrating to contribute since builds aren't clear to do locally. +## Done + +- added logging to scripts + ## TODO - reduce warnings - add scripts from nap theme here maybe - pygments highlighting -- From 824a6719fe7f39d2d5bf295270aab26cb5c12402 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Sat, 22 Feb 2025 15:17:45 -0800 Subject: [PATCH 21/21] no errors for make noplot --- docs/refactor.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/refactor.md b/docs/refactor.md index 8e33d0008..1e4a13dd0 100644 --- a/docs/refactor.md +++ b/docs/refactor.md @@ -9,9 +9,13 @@ ## Done - added logging to scripts +- fixed code copy ## TODO -- reduce warnings -- add scripts from nap theme here maybe +- reduce warnings (no warnings when make no plot) +- ~~add scripts from nap theme here maybe~~ - pygments highlighting +- headless on mac +- fix styling for This Page source +- search wtf keyboard shortcut (where did you go)