instaui 0.2.0__py2.py3-none-any.whl → 0.2.2__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. instaui/arco/component_types.py +389 -182
  2. instaui/arco/components/input.py +1 -1
  3. instaui/arco/components/typography.py +1 -1
  4. instaui/boot_info.py +2 -2
  5. instaui/components/component.py +5 -2
  6. instaui/components/container.py +32 -0
  7. instaui/components/element.py +11 -8
  8. instaui/components/heading.py +46 -0
  9. instaui/components/html/range.py +2 -2
  10. instaui/components/html/ul.py +2 -2
  11. instaui/components/match.py +2 -2
  12. instaui/components/mixins.py +8 -4
  13. instaui/components/vfor.py +8 -6
  14. instaui/event/web_event.py +7 -1
  15. instaui/fastapi_server/_utils.py +5 -21
  16. instaui/fastapi_server/dependency_router.py +5 -1
  17. instaui/fastapi_server/event_router.py +5 -5
  18. instaui/fastapi_server/request_context.py +5 -4
  19. instaui/fastapi_server/watch_router.py +2 -2
  20. instaui/patch_update.py +54 -0
  21. instaui/response.py +64 -0
  22. instaui/spa_router/_file_base_utils.py +1 -1
  23. instaui/static/insta-ui.css +1 -1
  24. instaui/static/insta-ui.esm-browser.prod.js +877 -825
  25. instaui/static/insta-ui.js.map +1 -1
  26. instaui/ui/__init__.py +33 -6
  27. instaui/ui/__init__.pyi +6 -0
  28. instaui/ui_functions/ui_types.py +6 -2
  29. instaui/ui_system_var_type.py +6 -0
  30. instaui/vars/mixin_types/element_binding.py +5 -1
  31. instaui/vars/mixin_types/observable.py +1 -1
  32. instaui/vars/mixin_types/py_binding.py +7 -0
  33. instaui/vars/vue_computed.py +5 -2
  34. instaui/watch/web_watch.py +10 -2
  35. instaui/webview/api.py +2 -23
  36. {instaui-0.2.0.dist-info → instaui-0.2.2.dist-info}/METADATA +1 -1
  37. {instaui-0.2.0.dist-info → instaui-0.2.2.dist-info}/RECORD +39 -34
  38. {instaui-0.2.0.dist-info → instaui-0.2.2.dist-info}/WHEEL +0 -0
  39. {instaui-0.2.0.dist-info → instaui-0.2.2.dist-info}/licenses/LICENSE +0 -0
@@ -15,7 +15,7 @@ class Input(Element):
15
15
  value: typing.Optional[TMaybeRef[str]] = None,
16
16
  **kwargs: Unpack[component_types.TInput],
17
17
  ):
18
- tag = f"a-input{'-'+ self._exten_name if self._exten_name else ''}"
18
+ tag = f"a-input{'-' + self._exten_name if self._exten_name else ''}"
19
19
  super().__init__(tag)
20
20
  try_setup_vmodel(self, value)
21
21
  self.props(handle_props(kwargs)) # type: ignore
@@ -17,7 +17,7 @@ class Typography(Element):
17
17
  text: typing.Optional[TMaybeRef[str]] = None,
18
18
  **kwargs: Unpack[component_types.TTypography],
19
19
  ):
20
- tag = f"a-typography{'-'+ self._exten_name if self._exten_name else ''}"
20
+ tag = f"a-typography{'-' + self._exten_name if self._exten_name else ''}"
21
21
  super().__init__(tag)
22
22
 
23
23
  if text is not None:
instaui/boot_info.py CHANGED
@@ -11,14 +11,14 @@ _colors = {
11
11
 
12
12
 
13
13
  def zero_boot_info(file: Path):
14
- message = f"""{_app_message('zero')}
14
+ message = f"""{_app_message("zero")}
15
15
  {_arrow_right()}file: {_with_color(str(file))}
16
16
  """
17
17
  print(message)
18
18
 
19
19
 
20
20
  def web_boot_info(ip: str):
21
- message = f"""{_app_message('web')}
21
+ message = f"""{_app_message("web")}
22
22
  {_arrow_right()}Local: {_with_color(str(ip), "blue")}
23
23
  """
24
24
  print(message)
@@ -11,11 +11,14 @@ from instaui.runtime import (
11
11
  check_default_app_slot_or_error,
12
12
  )
13
13
  from instaui.components.slot import SlotManager
14
- from instaui.vars.mixin_types.element_binding import ElementBindingMixin
14
+ from instaui.vars.mixin_types.element_binding import (
15
+ ElementBindingMixin,
16
+ ElementBindingProtocol,
17
+ )
15
18
 
16
19
 
17
20
  class Component(Jsonable):
18
- def __init__(self, tag: Optional[Union[str, ElementBindingMixin]] = None):
21
+ def __init__(self, tag: Optional[Union[str, ElementBindingProtocol]] = None):
19
22
  check_default_app_slot_or_error(
20
23
  "Not allowed to create element outside of ui.page"
21
24
  )
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+ from instaui.components.element import Element
3
+ from instaui.vars.types import TMaybeRef
4
+
5
+
6
+ class Container(Element):
7
+ """
8
+ Creates a layout container element with configurable width and spacing properties.
9
+
10
+ A flexible container component for structuring content layouts, providing controls for
11
+ maximum width and internal padding. The container is horizontally centered by default
12
+ through auto margins.
13
+
14
+ Args:
15
+ max_width (TMaybeRef[str], optional): Sets the maximum width of the container.
16
+ Accepts CSS width values (e.g., "800px", "100%", "75vw"). Defaults to "800px".
17
+ padding (TMaybeRef[str], optional): Controls internal spacing between container
18
+ edges and content. Accepts CSS padding values (e.g., "0.25rem", "1em", "10px").
19
+ Defaults to "0.25rem".
20
+ """
21
+
22
+ def __init__(
23
+ self,
24
+ max_width: TMaybeRef[str] = "800px",
25
+ *,
26
+ padding: TMaybeRef[str] = "0.25rem",
27
+ ):
28
+ super().__init__("div")
29
+
30
+ self.style({"max-width": max_width, "padding": padding}).style(
31
+ "margin-left:auto;margin-right:auto"
32
+ )
@@ -34,7 +34,10 @@ from .slot import SlotManager, Slot
34
34
  from instaui import consts
35
35
  from instaui.components.component import Component
36
36
 
37
- from instaui.vars.mixin_types.element_binding import ElementBindingMixin
37
+ from instaui.vars.mixin_types.element_binding import (
38
+ ElementBindingMixin,
39
+ ElementBindingProtocol,
40
+ )
38
41
 
39
42
  if TYPE_CHECKING:
40
43
  from instaui.event.event_mixin import EventMixin
@@ -79,7 +82,7 @@ class Element(Component):
79
82
  _default_classes: ClassVar[List[str]] = []
80
83
  _default_style: ClassVar[Dict[str, str]] = {}
81
84
 
82
- def __init__(self, tag: Optional[Union[str, ElementBindingMixin]] = None):
85
+ def __init__(self, tag: Optional[Union[str, ElementBindingProtocol]] = None):
83
86
  if self.dependency:
84
87
  tag = self.dependency.tag_name or ""
85
88
 
@@ -100,7 +103,7 @@ class Element(Component):
100
103
  self._directives: Dict[Directive, None] = {}
101
104
 
102
105
  self._slot_manager = SlotManager()
103
- self._element_ref: Optional[ElementRef] = None
106
+ self.__element_ref: Optional[ElementRef] = None
104
107
 
105
108
  def __init_subclass__(
106
109
  cls,
@@ -336,7 +339,7 @@ class Element(Component):
336
339
  self._directives[directive] = None
337
340
  return self
338
341
 
339
- def display(self, value: Union[ElementBindingMixin[bool], bool]) -> Self:
342
+ def display(self, value: Union[ElementBindingProtocol, bool]) -> Self:
340
343
  return self.directive(Directive(is_sys=False, name="vshow", value=value))
341
344
 
342
345
  def event_dataset(self, data: Any, name: str = "event-data") -> Self:
@@ -347,7 +350,7 @@ class Element(Component):
347
350
  return self
348
351
 
349
352
  def element_ref(self, ref: ElementRef):
350
- self._element_ref = ref
353
+ self.__element_ref = ref
351
354
  return self
352
355
 
353
356
  def update_dependencies(
@@ -464,10 +467,10 @@ class Element(Component):
464
467
  app_slot.get_temp_component_dependency(tag_name, self.dependency)
465
468
  )
466
469
 
467
- if self._element_ref:
470
+ if self.__element_ref:
468
471
  scope = get_current_scope()
469
- data["eRef"] = self._element_ref._to_element_config()
470
- scope.register_element_ref(self._element_ref)
472
+ data["eRef"] = self.__element_ref._to_element_config()
473
+ scope.register_element_ref(self.__element_ref)
471
474
 
472
475
  return data
473
476
 
@@ -0,0 +1,46 @@
1
+ from __future__ import annotations
2
+ from typing import Any, Union
3
+ from instaui.components.element import Element
4
+ from instaui.vars.types import TMaybeRef
5
+ from instaui import ui_system_var_type as ui_vars_type
6
+
7
+
8
+ class Heading(Element):
9
+ def __init__(
10
+ self,
11
+ text: Union[str, TMaybeRef[Any]],
12
+ *,
13
+ size: Union[TMaybeRef[str], ui_vars_type.TSize, None] = None,
14
+ weight: Union[TMaybeRef[str], ui_vars_type.TWeight, None] = None,
15
+ align: Union[TMaybeRef[str], ui_vars_type.TAlign, None] = None,
16
+ ):
17
+ """
18
+ Creates a heading element with customizable text content and styling properties.
19
+
20
+
21
+ Args:
22
+ text (Union[str, TMaybeRef[Any]]): The text content of the heading. Can be a static
23
+ string or a reactive reference (e.g., state object).
24
+ size (Union[TMaybeRef[str], TSize, None], optional): Controls the heading size.
25
+ Accepts values from "1" to "9". Defaults to None.
26
+ weight (Union[TMaybeRef[str], TWeight, None], optional): Sets font weight.
27
+ Acceptable values: "light", "regular", "medium", "bold". Defaults to None.
28
+ align (Union[TMaybeRef[str], TAlign, None], optional): Controls text alignment.
29
+ Valid options: "left", "center", "right". Defaults to None.
30
+
31
+ Example:
32
+ .. code-block:: python
33
+ size = ui.state("6")
34
+ text = ui.state("test")
35
+ align = ui.state("left")
36
+
37
+ arco.select(["1", "2", "3", "4", "5", "6", "7", "8", "9"], size)
38
+ arco.select(["left", "center", "right"], align, allow_clear=True)
39
+
40
+ with ui.container():
41
+ arco.input(text)
42
+ ui.heading(text, size=size, align=align)
43
+ """
44
+ super().__init__("heading")
45
+
46
+ self.props({"text": text, "size": size, "weight": weight, "align": align})
@@ -4,7 +4,7 @@ from instaui.components.element import Element
4
4
  from instaui.components.value_element import ValueElement
5
5
  from instaui import consts
6
6
  from instaui.vars.types import TMaybeRef
7
- from instaui.vars.mixin_types.element_binding import ElementBindingMixin
7
+ from instaui.vars.mixin_types.element_binding import ElementBindingProtocol
8
8
  from ._mixins import InputEventMixin
9
9
 
10
10
  _T_value = Union[int, float]
@@ -31,7 +31,7 @@ class Range(InputEventMixin, ValueElement[_T_value]):
31
31
 
32
32
  def vmodel(
33
33
  self,
34
- value: ElementBindingMixin,
34
+ value: ElementBindingProtocol,
35
35
  modifiers: Union[consts.TModifier, List[consts.TModifier], None] = None,
36
36
  *,
37
37
  prop_name: str = "value",
@@ -4,7 +4,7 @@ from instaui.components.element import Element
4
4
  from .li import Li
5
5
  from instaui.components.vfor import VFor
6
6
 
7
- from instaui.vars.mixin_types.element_binding import ElementBindingMixin
7
+ from instaui.vars.mixin_types.element_binding import ElementBindingProtocol
8
8
 
9
9
 
10
10
  class Ul(Element):
@@ -12,7 +12,7 @@ class Ul(Element):
12
12
  super().__init__("ul")
13
13
 
14
14
  @classmethod
15
- def from_list(cls, data: Union[List, ElementBindingMixin[List]]) -> Ul:
15
+ def from_list(cls, data: Union[List, ElementBindingProtocol]) -> Ul:
16
16
  with Ul() as ul:
17
17
  with VFor(data) as items:
18
18
  Li(items)
@@ -4,11 +4,11 @@ import typing
4
4
  from instaui.components.component import Component
5
5
  from instaui.runtime._app import new_scope
6
6
 
7
- from instaui.vars.mixin_types.element_binding import ElementBindingMixin
7
+ from instaui.vars.mixin_types.element_binding import ElementBindingProtocol
8
8
 
9
9
 
10
10
  class Match(Component):
11
- def __init__(self, on: ElementBindingMixin):
11
+ def __init__(self, on: ElementBindingProtocol):
12
12
  super().__init__("match")
13
13
  self._on = on
14
14
  self._default_case = None
@@ -1,12 +1,16 @@
1
- from typing import Dict, Protocol
1
+ from __future__ import annotations
2
+ from typing import Any, Dict, Protocol, TYPE_CHECKING, Union
2
3
  from typing_extensions import Self
3
4
  from instaui.vars.types import TMaybeRef
4
5
 
6
+ if TYPE_CHECKING:
7
+ from instaui.components.element import Element
8
+
5
9
 
6
10
  class PropsProtocol(Protocol):
7
- def props(self, props: Dict) -> Self: ...
11
+ def props(self, add: Union[str, Dict[str, Any], TMaybeRef]) -> Self: ...
8
12
 
9
13
 
10
14
  class CanDisabledMixin:
11
- def disabled(self: PropsProtocol, disabled: TMaybeRef[bool] = True):
12
- return self.props({"disabled": disabled})
15
+ def disabled(self: PropsProtocol, disabled: TMaybeRef[bool] = True) -> Element:
16
+ return self.props({"disabled": disabled}) # type: ignore
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
  from typing import (
3
3
  Dict,
4
- List,
5
4
  Literal,
6
5
  Mapping,
7
6
  Optional,
@@ -17,7 +16,10 @@ from instaui.components.component import Component
17
16
  from instaui.vars.vfor_item import VForItem, VForDict, VForWithIndex
18
17
  from instaui.runtime._app import get_app_slot, new_scope
19
18
 
20
- from instaui.vars.mixin_types.element_binding import ElementBindingMixin
19
+ from instaui.vars.mixin_types.element_binding import (
20
+ ElementBindingMixin,
21
+ ElementBindingProtocol,
22
+ )
21
23
 
22
24
  _T = TypeVar("_T")
23
25
 
@@ -25,7 +27,7 @@ _T = TypeVar("_T")
25
27
  class VFor(Component, Generic[_T]):
26
28
  def __init__(
27
29
  self,
28
- data: Union[Sequence[_T], ElementBindingMixin[List[_T]]],
30
+ data: Union[Sequence[_T], ElementBindingProtocol],
29
31
  *,
30
32
  key: Union[Literal["item", "index"], str] = "index",
31
33
  ):
@@ -117,10 +119,10 @@ class VFor(Component, Generic[_T]):
117
119
 
118
120
  @overload
119
121
  @classmethod
120
- def range(cls, end: ElementBindingMixin[int]) -> VFor[int]: ...
122
+ def range(cls, end: ElementBindingProtocol) -> VFor[int]: ...
121
123
 
122
124
  @classmethod
123
- def range(cls, end: Union[int, ElementBindingMixin[int]]) -> VFor[int]:
125
+ def range(cls, end: Union[int, ElementBindingProtocol]) -> VFor[int]:
124
126
  obj = cls(None) # type: ignore
125
127
 
126
128
  num = ( # type: ignore
@@ -135,6 +137,6 @@ class VFor(Component, Generic[_T]):
135
137
 
136
138
  @classmethod
137
139
  def from_dict(
138
- cls, data: Union[Mapping, pydantic.BaseModel, ElementBindingMixin[Dict]]
140
+ cls, data: Union[Mapping, pydantic.BaseModel, ElementBindingProtocol]
139
141
  ):
140
142
  return VForDict(VFor(data)) # type: ignore
@@ -3,7 +3,11 @@ import typing
3
3
  from typing_extensions import ParamSpec
4
4
  from instaui.common.jsonable import Jsonable
5
5
  from instaui.runtime._app import get_current_scope, get_app_slot
6
- from instaui.vars.mixin_types.py_binding import CanInputMixin, CanOutputMixin
6
+ from instaui.vars.mixin_types.py_binding import (
7
+ CanInputMixin,
8
+ CanOutputMixin,
9
+ _assert_outputs_be_can_output_mixin,
10
+ )
7
11
  from instaui.handlers import event_handler
8
12
  from instaui import pre_setup as _pre_setup
9
13
  from .event_mixin import EventMixin
@@ -27,6 +31,8 @@ class WebEvent(Jsonable, EventMixin, typing.Generic[P, R]):
27
31
  if pre_setup:
28
32
  _pre_setup._check_args(pre_setup)
29
33
 
34
+ _assert_outputs_be_can_output_mixin(outputs)
35
+
30
36
  self._inputs = inputs
31
37
  self._outputs = outputs
32
38
  self._fn = fn
@@ -1,12 +1,12 @@
1
- from typing import Any, Dict, List, Optional
1
+ from typing import Any, Dict, List, Optional, Sequence
2
2
  from instaui.runtime._app import get_app_slot
3
- from instaui.skip import is_skip_output
3
+ from instaui.response import response_data
4
4
  import pydantic
5
5
 
6
6
 
7
7
  class ResponseData(pydantic.BaseModel):
8
8
  values: Optional[List[Any]] = None
9
- skips: Optional[List[int]] = None
9
+ types: Optional[Sequence[int]] = None
10
10
 
11
11
 
12
12
  def update_app_page_info(data: Dict):
@@ -22,21 +22,5 @@ def update_app_page_info(data: Dict):
22
22
  app._query_params = page_info["queryParams"]
23
23
 
24
24
 
25
- def response_data(outputs_binding_count: int, result: Any):
26
- data = ResponseData()
27
- if outputs_binding_count > 0:
28
- if not isinstance(result, tuple):
29
- result = [result]
30
-
31
- result_infos = [(r, int(is_skip_output(r))) for r in result]
32
-
33
- if len(result_infos) == 1 and result_infos[0][1] == 1:
34
- return data
35
-
36
- data.values = [0 if info[1] == 1 else info[0] for info in result_infos]
37
- skips = [info[1] for info in result_infos]
38
-
39
- if sum(skips) > 0:
40
- data.skips = skips
41
-
42
- return data
25
+ def response_web_data(outputs_binding_count: int, result: Any):
26
+ return ResponseData(**response_data(outputs_binding_count, result))
@@ -16,7 +16,11 @@ def _dependency_handler(app: FastAPI):
16
16
  def _(hash_part: str, file_name: str) -> FileResponse:
17
17
  hash_part_with_extend_paths = hash_part.split("/", maxsplit=1)
18
18
  hash_part = hash_part_with_extend_paths[0]
19
- extend_path = None if len(hash_part_with_extend_paths) == 1 else hash_part_with_extend_paths[1]
19
+ extend_path = (
20
+ None
21
+ if len(hash_part_with_extend_paths) == 1
22
+ else hash_part_with_extend_paths[1]
23
+ )
20
24
 
21
25
  folder = resource.get_folder_path(hash_part)
22
26
  if extend_path:
@@ -20,14 +20,14 @@ def _async_handler(app: FastAPI):
20
20
  if handler is None:
21
21
  return {"error": "event handler not found"}
22
22
 
23
- assert inspect.iscoroutinefunction(
24
- handler.fn
25
- ), "handler must be a coroutine function"
23
+ assert inspect.iscoroutinefunction(handler.fn), (
24
+ "handler must be a coroutine function"
25
+ )
26
26
 
27
27
  _utils.update_app_page_info(data)
28
28
 
29
29
  result = await handler.fn(*handler.get_handler_args(_get_binds_from_data(data)))
30
- return _utils.response_data(handler.outputs_binding_count, result)
30
+ return _utils.response_web_data(handler.outputs_binding_count, result)
31
31
 
32
32
 
33
33
  def _sync_handler(app: FastAPI):
@@ -41,7 +41,7 @@ def _sync_handler(app: FastAPI):
41
41
 
42
42
  result = handler.fn(*handler.get_handler_args(_get_binds_from_data(data)))
43
43
 
44
- return _utils.response_data(handler.outputs_binding_count, result)
44
+ return _utils.response_web_data(handler.outputs_binding_count, result)
45
45
 
46
46
  if get_context().debug_mode:
47
47
 
@@ -3,17 +3,18 @@ from typing import Optional
3
3
  from fastapi import Request
4
4
  from contextvars import ContextVar, Token
5
5
 
6
- current_request_ctx :ContextVar[Optional[Request]]= ContextVar("current_request", default=None)
6
+ current_request_ctx: ContextVar[Optional[Request]] = ContextVar(
7
+ "current_request", default=None
8
+ )
7
9
 
8
10
 
9
-
10
- def set_current_request(request: Request) :
11
+ def set_current_request(request: Request):
11
12
  return current_request_ctx.set(request)
12
13
 
14
+
13
15
  def reset_current_request(token: Token) -> None:
14
16
  current_request_ctx.reset(token)
15
17
 
16
18
 
17
19
  def get_current_request() -> Request:
18
20
  return current_request_ctx.get() # type: ignore
19
-
@@ -24,7 +24,7 @@ def _async_handler(app: FastAPI):
24
24
  result = await handler_info.fn(
25
25
  *handler_info.get_handler_args(_get_binds_from_data(data))
26
26
  )
27
- return _utils.response_data(handler_info.outputs_binding_count, result)
27
+ return _utils.response_web_data(handler_info.outputs_binding_count, result)
28
28
 
29
29
 
30
30
  def _sync_handler(app: FastAPI):
@@ -40,7 +40,7 @@ def _sync_handler(app: FastAPI):
40
40
  result = handler_info.fn(
41
41
  *handler_info.get_handler_args(_get_binds_from_data(data))
42
42
  )
43
- return _utils.response_data(handler_info.outputs_binding_count, result)
43
+ return _utils.response_web_data(handler_info.outputs_binding_count, result)
44
44
 
45
45
  if get_context().debug_mode:
46
46
 
@@ -0,0 +1,54 @@
1
+ from typing import Any, Iterable, Sequence, Union
2
+ from instaui.common.jsonable import Jsonable
3
+
4
+
5
+ class PatchSetRecord:
6
+ def __init__(self, *, path: Sequence[Union[str, int]], value: Any):
7
+ self.path = list(path)
8
+ self.value = value
9
+
10
+
11
+ class PatchSet(Jsonable):
12
+ def __init__(self, records: Iterable[PatchSetRecord]):
13
+ self._records = list(records)
14
+
15
+ def patch_set(self, *, path: Sequence[Union[str, int]], value: Any):
16
+ return PatchSet([*self._records, PatchSetRecord(path=path, value=value)])
17
+
18
+ def _to_json_dict(self):
19
+ return [[r.path, r.value] for r in self._records]
20
+
21
+
22
+ def patch_set(*, path: Sequence[Union[str, int]], value: Any):
23
+ """
24
+ Generates a patch to specify how data should be updated.
25
+
26
+ This function is typically used within the return value of functions
27
+ used in `ui.event` or `ui.watch`, indicating the way data modifications are applied.
28
+
29
+ Args:
30
+ path (Sequence[Union[str, int]]): A sequence representing the path to the item that needs to be updated.
31
+ Each element can either be a string (for dictionary keys) or an integer
32
+ (for list indices).
33
+ value (Any): The new value to set at the specified path. Can be of any type.
34
+
35
+ Example:
36
+ .. code-block:: python
37
+
38
+ data = ui.state(
39
+ {
40
+ "v1": ["a", "b", "c"],
41
+ "v2": ["x", "y", "z"],
42
+ }
43
+ )
44
+
45
+ @ui.event(outputs=[data])
46
+ def update_data():
47
+ # update the second element of "v1" to "foo"
48
+ return ui.patch_set(path=["v1", 1], value="foo")
49
+
50
+ html.button("update data").on_click(update_data)
51
+ ui.label(data)
52
+ """
53
+
54
+ return PatchSet([PatchSetRecord(path=path, value=value)])
instaui/response.py ADDED
@@ -0,0 +1,64 @@
1
+ from typing import Any, List, Sequence, TypedDict
2
+ from enum import IntEnum
3
+ from instaui.common.jsonable import Jsonable
4
+ from instaui.skip import is_skip_output
5
+ from instaui.patch_update import PatchSet
6
+
7
+
8
+ class TResponse(TypedDict, total=False):
9
+ values: List[Any]
10
+ types: Sequence[int]
11
+
12
+
13
+ class ValueType(IntEnum):
14
+ VALUE = 0
15
+ SKIP = 1
16
+ Patch = 2
17
+
18
+
19
+ def response_data(outputs_binding_count: int, result: Any):
20
+ data: TResponse = {}
21
+ if outputs_binding_count > 0:
22
+ if not isinstance(result, tuple):
23
+ result = [result]
24
+
25
+ returns_count = len(result)
26
+
27
+ # [(value, 1), (value, 0)]
28
+ result_infos = [
29
+ (_try_get_value_from_jsonable(r), convert_type(r)) for r in result
30
+ ]
31
+
32
+ if returns_count == 1 and result_infos[0][1] == ValueType.SKIP:
33
+ return data
34
+
35
+ # fill missing values with None
36
+ if returns_count < outputs_binding_count:
37
+ result_infos.extend(
38
+ [(None, ValueType.SKIP)] * (outputs_binding_count - returns_count)
39
+ )
40
+
41
+ data["values"] = [
42
+ 0 if info[1] == ValueType.SKIP else info[0] for info in result_infos
43
+ ]
44
+ types = [info[1] for info in result_infos]
45
+
46
+ if sum(types) > 0:
47
+ data["types"] = types
48
+
49
+ return data
50
+
51
+
52
+ def convert_type(value: Any):
53
+ if is_skip_output(value):
54
+ return ValueType.SKIP
55
+ if isinstance(value, PatchSet):
56
+ return ValueType.Patch
57
+ return ValueType.VALUE
58
+
59
+
60
+ def _try_get_value_from_jsonable(value: Any) -> Any:
61
+ if isinstance(value, Jsonable):
62
+ return value._to_json_dict()
63
+
64
+ return value
@@ -113,7 +113,7 @@ class _model_utils:
113
113
  if not self.fn_path:
114
114
  return ""
115
115
 
116
- return f"from .{self.fn_path.replace(' ','_')} import main as {self.main_fn_name()}"
116
+ return f"from .{self.fn_path.replace(' ', '_')} import main as {self.main_fn_name()}"
117
117
 
118
118
  def main_fn_name(self):
119
119
  if not self.fn_path:
@@ -1 +1 @@
1
- :root{color-scheme:light dark}:where(body){--insta-column-gap: 1rem;height:100vh}:where(*){box-sizing:border-box;margin:0;padding:0}:where(#app){height:100%}:where(.app-box,.insta-main){height:100%;overflow-y:auto}:where(.insta-main){--insta-padding: 16px;padding:var(--insta-padding, 16px)}
1
+ .insta-themes:where([data-scaling="90%"]){--scaling: .9 }.insta-themes:where([data-scaling="95%"]){--scaling: .95 }.insta-themes:where([data-scaling="100%"]){--scaling: 1 }.insta-themes:where([data-scaling="105%"]){--scaling: 1.05 }.insta-themes:where([data-scaling="110%"]){--scaling: 1.1 }.insta-themes{--space-1: calc(4px* var(--scaling));--space-2: calc(8px* var(--scaling));--space-3: calc(12px* var(--scaling));--space-4: calc(16px* var(--scaling));--space-5: calc(24px* var(--scaling));--space-6: calc(32px* var(--scaling));--space-7: calc(40px* var(--scaling));--space-8: calc(48px* var(--scaling));--space-9: calc(64px* var(--scaling));--font-size-1: calc(12px* var(--scaling));--font-size-2: calc(14px* var(--scaling));--font-size-3: calc(16px* var(--scaling));--font-size-4: calc(18px* var(--scaling));--font-size-5: calc(20px* var(--scaling));--font-size-6: calc(24px* var(--scaling));--font-size-7: calc(28px* var(--scaling));--font-size-8: calc(35px* var(--scaling));--font-size-9: calc(60px* var(--scaling));--font-weight-light: 300;--font-weight-regular: 400;--font-weight-medium: 500;--font-weight-bold: 700;--line-height-1: calc(16px* var(--scaling));--line-height-2: calc(20px* var(--scaling));--line-height-3: calc(24px* var(--scaling));--line-height-4: calc(26px* var(--scaling));--line-height-5: calc(28px* var(--scaling));--line-height-6: calc(30px* var(--scaling));--line-height-7: calc(36px* var(--scaling));--line-height-8: calc(40px* var(--scaling));--line-height-9: calc(60px* var(--scaling));--letter-spacing-1: .0025em;--letter-spacing-2: 0em;--letter-spacing-3: 0em;--letter-spacing-4: -.0025em;--letter-spacing-5: -.005em;--letter-spacing-6: -.00625em;--letter-spacing-7: -.0075em;--letter-spacing-8: -.01em;--letter-spacing-9: -.025em;--default-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI (Custom)", Roboto, "Helvetica Neue", "Open Sans (Custom)", system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";--default-font-size: var(--font-size-3);--default-font-style: normal;--default-font-weight: var(--font-weight-regular);--default-line-height: 1.5;--default-letter-spacing: 0em;--default-leading-trim-start: .42em;--default-leading-trim-end: .36em;--heading-font-family: var(--default-font-family);--heading-font-size-adjust: 1;--heading-font-style: normal;--heading-leading-trim-start: var(--default-leading-trim-start);--heading-leading-trim-end: var(--default-leading-trim-end);--heading-letter-spacing: 0em;--heading-line-height-1: calc(16px* var(--scaling));--heading-line-height-2: calc(18px* var(--scaling));--heading-line-height-3: calc(22px* var(--scaling));--heading-line-height-4: calc(24px* var(--scaling));--heading-line-height-5: calc(26px* var(--scaling));--heading-line-height-6: calc(30px* var(--scaling));--heading-line-height-7: calc(36px* var(--scaling));--heading-line-height-8: calc(40px* var(--scaling));--heading-line-height-9: calc(60px* var(--scaling));--strong-font-family: var(--default-font-family);--strong-font-size-adjust: 1;--strong-font-style: inherit;--strong-font-weight: var(--font-weight-bold);--strong-letter-spacing: 0em;--em-font-family: "Times New Roman", "Times", serif;--em-font-size-adjust: 1.18;--em-font-style: italic;--em-font-weight: inherit;--em-letter-spacing: -.025em;overflow-wrap:break-word;font-family:var(--default-font-family);font-size:var(--default-font-size);font-weight:var(--default-font-weight);font-style:var(--default-font-style);line-height:var(--default-line-height);letter-spacing:var(--default-letter-spacing);-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--container-1: 448px;--container-2: 688px;--container-3: 880px;--container-4: 1136px}.i-weight-light{font-weight:var(--font-weight-light)}.i-weight-regular{font-weight:var(--font-weight-regular)}.i-weight-medium{font-weight:var(--font-weight-medium)}.i-weight-bold{font-weight:var(--font-weight-bold)}.i-text-align-left{text-align:left}.i-text-align-center{text-align:center}.i-text-align-right{text-align:right}.insta-Heading:where(.i-size-1){font-size:calc(var(--font-size-1) * var(--heading-font-size-adjust));--line-height: var(--heading-line-height-1);letter-spacing:calc(var(-letter-spacing-1) + var(--heading-letter-spacing))}.insta-Heading:where(.i-size-2){font-size:calc(var(--font-size-2) * var(--heading-font-size-adjust));--line-height: var(--heading-line-height-2);letter-spacing:calc(var(-letter-spacing-2) + var(--heading-letter-spacing))}.insta-Heading:where(.i-size-3){font-size:calc(var(--font-size-3) * var(--heading-font-size-adjust));--line-height: var(--heading-line-height-3);letter-spacing:calc(var(-letter-spacing-3) + var(--heading-letter-spacing))}.insta-Heading:where(.i-size-4){font-size:calc(var(--font-size-4) * var(--heading-font-size-adjust));--line-height: var(--heading-line-height-4);letter-spacing:calc(var(-letter-spacing-4) + var(--heading-letter-spacing))}.insta-Heading:where(.i-size-5){font-size:calc(var(--font-size-5) * var(--heading-font-size-adjust));--line-height: var(--heading-line-height-5);letter-spacing:calc(var(-letter-spacing-5) + var(--heading-letter-spacing))}.insta-Heading:where(.i-size-6){font-size:calc(var(--font-size-6) * var(--heading-font-size-adjust));--line-height: var(--heading-line-height-6);letter-spacing:calc(var(-letter-spacing-6) + var(--heading-letter-spacing))}.insta-Heading:where(.i-size-7){font-size:calc(var(--font-size-7) * var(--heading-font-size-adjust));--line-height: var(--heading-line-height-7);letter-spacing:calc(var(-letter-spacing-7) + var(--heading-letter-spacing))}.insta-Heading:where(.i-size-8){font-size:calc(var(--font-size-8) * var(--heading-font-size-adjust));--line-height: var(--heading-line-height-8);letter-spacing:calc(var(-letter-spacing-8) + var(--heading-letter-spacing))}.insta-Heading:where(.i-size-9){font-size:calc(var(--font-size-9) * var(--heading-font-size-adjust));--line-height: var(--heading-line-height-9);letter-spacing:calc(var(-letter-spacing-9) + var(--heading-letter-spacing))}:root{color-scheme:light dark}:where(body){--insta-column-gap: 1rem;height:100vh}:where(*){box-sizing:border-box;margin:0;padding:0}:where(#app){height:100%}:where(.app-box,.insta-main){height:100%;overflow-y:auto}:where(.insta-main){--insta-padding: 16px;padding:var(--insta-padding, 16px)}