-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Deployed 95117e7 with MkDocs version: 1.6.0
- Loading branch information
Unknown
committed
Jul 21, 2024
0 parents
commit afd93c0
Showing
121 changed files
with
61,351 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
Large diffs are not rendered by default.
Oops, something went wrong.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import json | ||
from pathlib import Path | ||
from textwrap import dedent | ||
|
||
import mkdocs_gen_files | ||
from pymmcore_plus.core import _mmcore_plus | ||
|
||
WIDGET_LIST = Path(__file__).parent / "widget_list.json" | ||
WIDGETS = Path(__file__).parent / "widgets" | ||
EXAMPLES = Path(__file__).parent.parent / "examples" | ||
TEMPLATE = """ | ||
<figure markdown> | ||
![{widget} widget](../{img}){{ loading=lazy, class="widget-image" }} | ||
<figcaption> | ||
This image generated from <a href="#example">example code below</a>. | ||
</figcaption> | ||
</figure> | ||
::: pymmcore_widgets.{widget} | ||
## Example | ||
```python linenums="1" title="{snake}.py" | ||
--8<-- "examples/{snake}.py" | ||
``` | ||
""" | ||
|
||
|
||
def _camel_to_snake(name: str) -> str: | ||
import re | ||
|
||
s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name) | ||
return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower() | ||
|
||
|
||
SEEN: set[int] = set() | ||
|
||
|
||
def _example_screenshot(cls_name: str, dest: str) -> None: | ||
path = EXAMPLES / f"{_camel_to_snake(cls_name)}.py" | ||
if not path.exists(): | ||
raise ValueError(f"Could not find example: {path}") | ||
|
||
from qtpy.QtWidgets import QApplication | ||
|
||
src = path.read_text().strip() | ||
src = src.replace("QApplication([])", "QApplication.instance() or QApplication([])") | ||
src = src.replace("app.exec_()", "") | ||
src = src.replace("app.exec()", "") | ||
gl = {**globals().copy(), "__name__": "__main__"} | ||
exec(src, gl, gl) | ||
|
||
app = QApplication.instance() or QApplication([]) | ||
new = [w for w in app.topLevelWidgets() if id(w) not in SEEN] | ||
# remove all classes that are Qframe or QMenu | ||
new = [w for w in new if w.__class__.__name__ not in ["QFrame", "QMenu"]] | ||
SEEN.update(id(w) for w in new) | ||
if new: | ||
widget = next((w for w in new if w.__class__.__name__ == cls_name), new[0]) | ||
widget.setMinimumWidth(300) # turns out this is very important for grab | ||
widget.grab().save(dest) | ||
|
||
# clean up core instance and application | ||
del _mmcore_plus._instance | ||
_mmcore_plus._instance = None | ||
for w in app.topLevelWidgets(): | ||
w.deleteLater() | ||
|
||
|
||
def _generate_widget_page(widget: str) -> None: | ||
"""Auto-Generate pages in the widgets folder.""" | ||
filename = f"widgets/{widget}.md" | ||
snake = _camel_to_snake(widget) | ||
print("Generating", filename) | ||
img = f"images/{snake}.png" | ||
with mkdocs_gen_files.open(img, "wb") as f: | ||
_example_screenshot(widget, f.name) | ||
|
||
with mkdocs_gen_files.open(filename, "w") as f: | ||
f.write(dedent(TEMPLATE.format(widget=widget, snake=snake, img=img))) | ||
|
||
mkdocs_gen_files.set_edit_path(filename, Path(__file__).name) | ||
|
||
|
||
def _generate_widget_pages() -> None: | ||
# it would be nice to do this in parallel, | ||
# but mkdocs_gen_files doesn't work well with multiprocessing | ||
with open(WIDGET_LIST) as f: | ||
widget_dict = json.load(f) | ||
|
||
for _, widgets in widget_dict.items(): | ||
for widget in widgets: | ||
# skip classes that have manual examples | ||
if not (WIDGETS / f"{widget}.md").exists(): | ||
_generate_widget_page(widget) | ||
|
||
|
||
_generate_widget_pages() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import json | ||
from pathlib import Path | ||
from typing import Any, cast | ||
|
||
from qtpy.QtWidgets import QWidget | ||
|
||
import pymmcore_widgets | ||
|
||
WIDGET_LIST = Path(__file__).parent / "widget_list.json" | ||
|
||
|
||
def on_page_markdown(md: str, **_: Any) -> str: | ||
"""Called when the markdown for a page is loaded.""" | ||
with open(WIDGET_LIST) as f: | ||
widget_dict = json.load(f) | ||
|
||
for section, widget_list in widget_dict.items(): | ||
# e.g. {{ CONFIGURATION_WIDGETS }} in index.md | ||
section_key = "{{ " + cast(str, section).upper() + " }}" | ||
if section_key in md: | ||
md = md.replace(section_key, _widget_table(widget_list)) | ||
return md | ||
|
||
|
||
def _widget_table(widget_list: list[str]) -> str: | ||
table = ["| Widget | Description |", "| ------ | ----------- |"] | ||
for name in dir(pymmcore_widgets): | ||
if name.startswith("_") or name not in widget_list: | ||
continue | ||
obj = getattr(pymmcore_widgets, name) | ||
if isinstance(obj, type) and issubclass(obj, QWidget): | ||
doc = (obj.__doc__ or "").strip().splitlines()[0] | ||
table.append(f"| [{name}]({name}.md) | {doc} |") | ||
|
||
return "\n".join(table) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
|
||
/* Avoid breaking parameter names, etc. in table cells. */ | ||
.doc-contents td code { | ||
word-break: normal !important; | ||
} | ||
|
||
/* No line break before first paragraph of descriptions. */ | ||
.doc-md-description, | ||
.doc-md-description>p:first-child { | ||
display: inline; | ||
} | ||
|
||
/* Max width for docstring sections tables. */ | ||
.doc .md-typeset__table, | ||
.doc .md-typeset__table table { | ||
display: table !important; | ||
width: 100%; | ||
} | ||
|
||
.doc .md-typeset__table tr { | ||
display: table-row; | ||
} | ||
|
||
/* Defaults in Spacy table style. */ | ||
.doc-param-default { | ||
float: right; | ||
} | ||
|
||
/* Backward-compatibility: docstring section titles in bold. */ | ||
.doc-section-title { | ||
font-weight: bold; | ||
} | ||
|
||
/* Symbols in Navigation and ToC. */ | ||
:root, | ||
[data-md-color-scheme="default"] { | ||
--doc-symbol-attribute-fg-color: #953800; | ||
--doc-symbol-function-fg-color: #8250df; | ||
--doc-symbol-method-fg-color: #8250df; | ||
--doc-symbol-class-fg-color: #0550ae; | ||
--doc-symbol-module-fg-color: #5cad0f; | ||
|
||
--doc-symbol-attribute-bg-color: #9538001a; | ||
--doc-symbol-function-bg-color: #8250df1a; | ||
--doc-symbol-method-bg-color: #8250df1a; | ||
--doc-symbol-class-bg-color: #0550ae1a; | ||
--doc-symbol-module-bg-color: #5cad0f1a; | ||
} | ||
|
||
[data-md-color-scheme="slate"] { | ||
--doc-symbol-attribute-fg-color: #ffa657; | ||
--doc-symbol-function-fg-color: #d2a8ff; | ||
--doc-symbol-method-fg-color: #d2a8ff; | ||
--doc-symbol-class-fg-color: #79c0ff; | ||
--doc-symbol-module-fg-color: #baff79; | ||
|
||
--doc-symbol-attribute-bg-color: #ffa6571a; | ||
--doc-symbol-function-bg-color: #d2a8ff1a; | ||
--doc-symbol-method-bg-color: #d2a8ff1a; | ||
--doc-symbol-class-bg-color: #79c0ff1a; | ||
--doc-symbol-module-bg-color: #baff791a; | ||
} | ||
|
||
code.doc-symbol { | ||
border-radius: .1rem; | ||
font-size: .85em; | ||
padding: 0 .3em; | ||
font-weight: bold; | ||
} | ||
|
||
code.doc-symbol-attribute { | ||
color: var(--doc-symbol-attribute-fg-color); | ||
background-color: var(--doc-symbol-attribute-bg-color); | ||
} | ||
|
||
code.doc-symbol-attribute::after { | ||
content: "attr"; | ||
} | ||
|
||
code.doc-symbol-function { | ||
color: var(--doc-symbol-function-fg-color); | ||
background-color: var(--doc-symbol-function-bg-color); | ||
} | ||
|
||
code.doc-symbol-function::after { | ||
content: "func"; | ||
} | ||
|
||
code.doc-symbol-method { | ||
color: var(--doc-symbol-method-fg-color); | ||
background-color: var(--doc-symbol-method-bg-color); | ||
} | ||
|
||
code.doc-symbol-method::after { | ||
content: "meth"; | ||
} | ||
|
||
code.doc-symbol-class { | ||
color: var(--doc-symbol-class-fg-color); | ||
background-color: var(--doc-symbol-class-bg-color); | ||
} | ||
|
||
code.doc-symbol-class::after { | ||
content: "class"; | ||
} | ||
|
||
code.doc-symbol-module { | ||
color: var(--doc-symbol-module-fg-color); | ||
background-color: var(--doc-symbol-module-bg-color); | ||
} | ||
|
||
code.doc-symbol-module::after { | ||
content: "mod"; | ||
} | ||
|
||
.doc-signature .autorefs { | ||
color: inherit; | ||
border-bottom: 1px dotted currentcolor; | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.