-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Woohoo! Autogenerator is working. Added html for QR Wifi generator
- Loading branch information
1 parent
b5d4efc
commit 7f28a4f
Showing
11 changed files
with
347 additions
and
3 deletions.
There are no files selected for viewing
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
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
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,169 @@ | ||
""" | ||
WIP. | ||
This is a module that generates a `panel` app for a function. | ||
It's in some places specific for `typer` and needs a lot of work to be more generic. | ||
For now - it allows me to generate some `panel` code for functions. | ||
""" | ||
|
||
import enum | ||
import typing | ||
from collections.abc import Callable | ||
from typing import Optional | ||
from typing import TypedDict | ||
|
||
import panel as pn | ||
import PIL | ||
|
||
|
||
def _get_all_args_and_kwargs_names(function: Callable) -> tuple: | ||
args = function.__code__.co_varnames[: function.__code__.co_argcount] | ||
kw_start_index = function.__code__.co_argcount | ||
kw_end_index = kw_start_index + function.__code__.co_kwonlyargcount | ||
kwargs = function.__code__.co_varnames[function.__code__.co_argcount : kw_end_index] | ||
return args, kwargs | ||
|
||
|
||
def get_type_of_arg(function: Callable, arg_name: str) -> str: | ||
try: | ||
type_ = function.__annotations__.get(arg_name).__args__ | ||
return type_[0] | ||
except (AttributeError, IndexError): | ||
return function.__annotations__.get(arg_name, typing.Any) | ||
|
||
|
||
class WidgetDict(TypedDict): | ||
widget: pn.widgets.Widget | ||
args_factory: Optional[Callable] | ||
|
||
|
||
PANEL_ELEMENTS_MAP: dict[type, WidgetDict] = { | ||
int: WidgetDict(widget=pn.widgets.IntSlider, args_factory=None), | ||
bool: WidgetDict(widget=pn.widgets.Checkbox, args_factory=None), | ||
str: WidgetDict(widget=pn.widgets.TextInput, args_factory=None), | ||
float: WidgetDict(widget=pn.widgets.FloatSlider, args_factory=None), | ||
enum.Enum: WidgetDict(widget=pn.widgets.Select, args_factory=lambda enum_: {"options": [e.value for e in enum_]}), | ||
} | ||
|
||
_PANEL_RESULTS_MAP = { | ||
str: pn.pane.Str, | ||
PIL.Image.Image: pn.pane.PNG, | ||
} | ||
|
||
|
||
def get_help_for_arg(function: Callable, arg_name: str) -> str | None: | ||
arg = function.__annotations__.get(arg_name, None) | ||
try: | ||
return arg.__metadata__[0].help | ||
except AttributeError: | ||
return None | ||
|
||
|
||
def generate_panel_code( # noqa: C901,PLR0915 | ||
function: Callable, | ||
*, | ||
default_args_values: Optional[dict[str, typing.Any]] = None, | ||
args_to_skip: Optional[list[str]] = None, | ||
additional_widget_map: Optional[dict[type, pn.widgets.Widget]] = None, | ||
) -> str: | ||
if default_args_values is None: | ||
default_args_values = {} | ||
if args_to_skip is None: | ||
args_to_skip = [] | ||
if additional_widget_map is None: | ||
additional_widget_map = {} | ||
args, kwargs = _get_all_args_and_kwargs_names(function) | ||
|
||
args_types = {arg_name: get_type_of_arg(function, arg_name) for arg_name in args} | ||
kwargs_types = {kwarg_name: get_type_of_arg(function, kwarg_name) for kwarg_name in kwargs} | ||
|
||
widgets = {} | ||
|
||
elements_map = {**PANEL_ELEMENTS_MAP, **additional_widget_map} | ||
|
||
for arg_name, arg_type in [*args_types.items(), *kwargs_types.items()]: | ||
if arg_name in args_to_skip: | ||
continue | ||
widget_dict = elements_map.get(arg_type, None) | ||
if widget_dict is None: | ||
continue | ||
args_factory = widget_dict.get("args_factory", None) | ||
|
||
def widget_factory_wrapper(*, widget_dict, args_factory, arg_type): | ||
def widget_factory(*args, **kwargs): | ||
additional_args = {} | ||
|
||
if args_factory is not None: | ||
additional_args = args_factory(arg_type) | ||
|
||
return widget_dict["widget"](*args, **kwargs, **additional_args) | ||
|
||
return widget_factory | ||
|
||
widgets[arg_name] = widget_factory_wrapper( | ||
widget_dict=widget_dict, | ||
args_factory=args_factory, | ||
arg_type=arg_type, | ||
) | ||
|
||
function_name = " ".join(function.__name__.upper().split("_")) | ||
|
||
doc_of_function = function.__doc__ or None | ||
if doc_of_function: | ||
header = pn.pane.Markdown( | ||
f""" | ||
# {function_name} | ||
**{doc_of_function}** | ||
""".strip(), | ||
) | ||
|
||
widgets_list = [] | ||
for arg_name, widget_type in widgets.items(): | ||
name = arg_name | ||
if help_text := get_help_for_arg(function, arg_name): | ||
name = f"{arg_name} ({help_text})" | ||
value = default_args_values.get(arg_name, None) | ||
widget_kwargs = {"name": name} | ||
if value is not None: | ||
widget_kwargs["value"] = value | ||
|
||
pass | ||
# widget_kwargs["options"] = [e.name for e in arg_type] | ||
widgets_list.append(widget_type(**widget_kwargs)) | ||
|
||
button = pn.widgets.Button(name="Run", button_type="primary") | ||
widgets_list.append(button) | ||
|
||
args_column = pn.Column(*widgets_list) | ||
|
||
results_container = pn.Column(pn.pane.Markdown("# Result")) | ||
|
||
results_column = pn.Column() | ||
|
||
def _run(column: pn.Column, clicked: pn.widgets.Button): | ||
if not clicked: | ||
return | ||
|
||
func_args = [] | ||
for widget in column: | ||
for arg_name in [*args, *kwargs]: | ||
if not widget.name.startswith(arg_name): | ||
continue | ||
func_args.append(widget.value) | ||
result = function(*func_args) | ||
results_column.clear() | ||
|
||
results_type = type(result) | ||
|
||
result_widget = _PANEL_RESULTS_MAP.get(results_type, pn.pane.Str)(result) | ||
results_column.append(result_widget) | ||
results_container.append(results_column) | ||
row.append(results_container) | ||
|
||
_runner = pn.bind(_run, args_column, clicked=button) | ||
args_column.append(_runner) | ||
row = pn.Row(pn.Column(header, args_column)) | ||
|
||
return pn.WidgetBox(row) |
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,47 @@ | ||
<html> | ||
<head> | ||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> | ||
<script defer src="https://pyscript.net/latest/pyscript.js"></script> | ||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-3.2.1.js"></script> | ||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.2.1.min.js"></script> | ||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.2.1.min.js"></script> | ||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@holoviz/[email protected]/dist/panel.min.js"></script> | ||
|
||
<style> | ||
|
||
</style> | ||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous"> | ||
|
||
</head> | ||
<py-config type="toml"> | ||
packages = [ | ||
"qrcode", | ||
"pillow", | ||
"typer", | ||
"https://cdn.holoviz.org/panel/1.2.1/dist/wheels/bokeh-3.2.1-py3-none-any.whl", | ||
"https://cdn.holoviz.org/panel/1.2.1/dist/wheels/panel-1.2.1-py3-none-any.whl" | ||
] | ||
[[fetch]] | ||
files = ["./index.py"] | ||
[[fetch]] | ||
from = "../../bucket_of_utils/qr/wifi.py" | ||
to_folder = "bucket_of_utils/qr" | ||
[[fetch]] | ||
from = "../../bucket_of_utils/panel_autogenerator/main.py" | ||
to_folder = "bucket_of_utils/panel_autogenerator" | ||
[[fetch]] | ||
from = "https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/ttf" | ||
files = ["FiraCode-Regular.ttf"] | ||
to_folder = "_static/fonts" | ||
|
||
</py-config> | ||
|
||
<body> | ||
<main class="container row" id="main"> | ||
</main> | ||
<py-script src="./index.py"></py-script> | ||
<py-script> </py-script> | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script> | ||
</body> | ||
|
||
</html> |
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,23 @@ | ||
import enum | ||
|
||
from bucket_of_utils.panel_autogenerator.main import PANEL_ELEMENTS_MAP | ||
from bucket_of_utils.panel_autogenerator.main import WidgetDict | ||
from bucket_of_utils.panel_autogenerator.main import generate_panel_code | ||
from bucket_of_utils.qr.wifi import SecurityTypes | ||
from bucket_of_utils.qr.wifi import generate_qr_code | ||
|
||
default_args_values = { | ||
"security": "WPA", | ||
"hidden": False, | ||
} | ||
additional_widget_map: dict[type:WidgetDict] = { | ||
SecurityTypes: PANEL_ELEMENTS_MAP[enum.Enum], | ||
} | ||
|
||
widget_box = generate_panel_code( | ||
generate_qr_code, | ||
args_to_skip=["directory_to_save_qr_code", "overwrite"], | ||
default_args_values=default_args_values, | ||
additional_widget_map=additional_widget_map, | ||
) | ||
widget_box.servable(target="main") |
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
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
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
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
Oops, something went wrong.