violit 0.0.5__py3-none-any.whl → 0.0.6__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.
- violit/component.py +38 -38
- violit/state.py +201 -0
- violit/widgets/chart_widgets.py +253 -253
- violit/widgets/data_widgets.py +27 -9
- violit/widgets/input_widgets.py +745 -745
- violit/widgets/status_widgets.py +308 -255
- violit/widgets/text_widgets.py +154 -109
- {violit-0.0.5.dist-info → violit-0.0.6.dist-info}/METADATA +1 -1
- {violit-0.0.5.dist-info → violit-0.0.6.dist-info}/RECORD +12 -12
- {violit-0.0.5.dist-info → violit-0.0.6.dist-info}/WHEEL +0 -0
- {violit-0.0.5.dist-info → violit-0.0.6.dist-info}/licenses/LICENSE +0 -0
- {violit-0.0.5.dist-info → violit-0.0.6.dist-info}/top_level.txt +0 -0
violit/widgets/text_widgets.py
CHANGED
|
@@ -6,82 +6,98 @@ from ..context import rendering_ctx
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class TextWidgetsMixin:
|
|
9
|
-
def write(self, *args,
|
|
10
|
-
"""
|
|
11
|
-
from ..state import State
|
|
12
|
-
import re
|
|
13
|
-
import json
|
|
14
|
-
import html as html_lib
|
|
9
|
+
def write(self, *args, **kwargs):
|
|
10
|
+
"""Magic write: displays arguments based on their type
|
|
15
11
|
|
|
16
|
-
|
|
12
|
+
Supported types:
|
|
13
|
+
- Strings, Numbers, State: Rendered as Markdown text
|
|
14
|
+
- Pandas DataFrame/Series: Rendered as interactive table
|
|
15
|
+
- Dict/List: Rendered as JSON tree
|
|
16
|
+
- Matplotlib/Plotly Figures: Rendered as charts
|
|
17
|
+
- Exceptions: Rendered as error trace
|
|
18
|
+
"""
|
|
19
|
+
from ..state import State, ComputedState
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
]
|
|
30
|
-
for pattern in markdown_patterns:
|
|
31
|
-
if re.search(pattern, text, re.MULTILINE):
|
|
32
|
-
return True
|
|
33
|
-
return False
|
|
21
|
+
# Buffer for text-like arguments
|
|
22
|
+
text_buffer = []
|
|
23
|
+
|
|
24
|
+
def flush_buffer():
|
|
25
|
+
if text_buffer:
|
|
26
|
+
self.markdown(*text_buffer)
|
|
27
|
+
text_buffer.clear()
|
|
28
|
+
|
|
29
|
+
for arg in args:
|
|
30
|
+
# Unwrap state for type checking ONLY
|
|
31
|
+
check_val = arg.value if isinstance(arg, (State, ComputedState)) else arg
|
|
34
32
|
|
|
35
|
-
#
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
# 1. Pandas DataFrame / Series
|
|
34
|
+
is_df = False
|
|
35
|
+
try:
|
|
36
|
+
import pandas as pd
|
|
37
|
+
if isinstance(check_val, (pd.DataFrame, pd.Series, pd.Index)):
|
|
38
|
+
is_df = True
|
|
39
|
+
except ImportError: pass
|
|
38
40
|
|
|
41
|
+
if is_df:
|
|
42
|
+
flush_buffer()
|
|
43
|
+
if hasattr(self, 'dataframe'):
|
|
44
|
+
self.dataframe(arg)
|
|
45
|
+
else:
|
|
46
|
+
self.markdown(str(arg))
|
|
47
|
+
continue
|
|
48
|
+
|
|
49
|
+
# 2. Matplotlib Figure
|
|
50
|
+
is_pyplot = False
|
|
39
51
|
try:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
# DataFrame (pandas)
|
|
52
|
-
try:
|
|
53
|
-
import pandas as pd
|
|
54
|
-
if isinstance(current_value, pd.DataFrame):
|
|
55
|
-
parts.append(self._render_dataframe_html(current_value))
|
|
56
|
-
continue
|
|
57
|
-
except (ImportError, AttributeError):
|
|
58
|
-
pass
|
|
59
|
-
|
|
60
|
-
# Dict or List → JSON
|
|
61
|
-
if isinstance(current_value, (dict, list, tuple)):
|
|
62
|
-
json_str = json.dumps(current_value, indent=2, ensure_ascii=False)
|
|
63
|
-
parts.append(f'<pre style="background:var(--sl-bg-card);padding:1rem;border-radius:0.5rem;border:1px solid var(--sl-border);overflow-x:auto;"><code style="color:var(--sl-text);font-family:monospace;">{html_lib.escape(json_str)}</code></pre>')
|
|
64
|
-
continue
|
|
65
|
-
|
|
66
|
-
# String with markdown → render as markdown
|
|
67
|
-
text = str(current_value)
|
|
68
|
-
if _has_markdown(text):
|
|
69
|
-
parts.append(self._render_markdown(text))
|
|
70
|
-
else:
|
|
71
|
-
# Plain text
|
|
72
|
-
parts.append(text)
|
|
52
|
+
import matplotlib.figure
|
|
53
|
+
if isinstance(check_val, matplotlib.figure.Figure):
|
|
54
|
+
is_pyplot = True
|
|
55
|
+
except ImportError: pass
|
|
56
|
+
|
|
57
|
+
if is_pyplot:
|
|
58
|
+
flush_buffer()
|
|
59
|
+
if hasattr(self, 'pyplot'):
|
|
60
|
+
self.pyplot(arg)
|
|
61
|
+
continue
|
|
73
62
|
|
|
74
|
-
|
|
75
|
-
|
|
63
|
+
# 3. Plotly Figure
|
|
64
|
+
is_plotly = False
|
|
65
|
+
try:
|
|
66
|
+
if hasattr(check_val, 'to_plotly_json'):
|
|
67
|
+
is_plotly = True
|
|
68
|
+
except ImportError: pass
|
|
69
|
+
|
|
70
|
+
if is_plotly:
|
|
71
|
+
flush_buffer()
|
|
72
|
+
if hasattr(self, 'plotly_chart'):
|
|
73
|
+
self.plotly_chart(arg)
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
# 4. Dict / List (JSON)
|
|
77
|
+
if isinstance(check_val, (dict, list)):
|
|
78
|
+
flush_buffer()
|
|
79
|
+
if hasattr(self, 'json'):
|
|
80
|
+
self.json(arg)
|
|
81
|
+
else:
|
|
82
|
+
# Fallback if json widget logic is missing for State
|
|
83
|
+
# But wait, we need to fix json widget too.
|
|
84
|
+
self.json(arg)
|
|
85
|
+
continue
|
|
76
86
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
# 5. Exception
|
|
88
|
+
if isinstance(check_val, Exception):
|
|
89
|
+
flush_buffer()
|
|
90
|
+
if hasattr(self, 'exception'):
|
|
91
|
+
self.exception(arg)
|
|
92
|
+
else:
|
|
93
|
+
self.error(str(arg))
|
|
94
|
+
continue
|
|
80
95
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
# Default: Text-like (str, int, float, State, ComputedState)
|
|
97
|
+
text_buffer.append(arg)
|
|
98
|
+
|
|
99
|
+
# Flush remaining text
|
|
100
|
+
flush_buffer()
|
|
85
101
|
|
|
86
102
|
def _render_markdown(self, text: str) -> str:
|
|
87
103
|
"""Render markdown to HTML (internal helper)"""
|
|
@@ -191,20 +207,25 @@ class TextWidgetsMixin:
|
|
|
191
207
|
'''
|
|
192
208
|
return styled_html
|
|
193
209
|
|
|
194
|
-
def heading(self,
|
|
210
|
+
def heading(self, *args, level: int = 1, divider: bool = False):
|
|
195
211
|
"""Display heading (h1-h6)"""
|
|
196
|
-
from ..state import State
|
|
212
|
+
from ..state import State, ComputedState
|
|
197
213
|
import html as html_lib
|
|
198
214
|
|
|
199
215
|
cid = self._get_next_cid("heading")
|
|
200
216
|
def builder():
|
|
201
217
|
token = rendering_ctx.set(cid)
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
218
|
+
|
|
219
|
+
parts = []
|
|
220
|
+
for arg in args:
|
|
221
|
+
if isinstance(arg, (State, ComputedState)):
|
|
222
|
+
parts.append(str(arg.value))
|
|
223
|
+
elif callable(arg):
|
|
224
|
+
parts.append(str(arg()))
|
|
225
|
+
else:
|
|
226
|
+
parts.append(str(arg))
|
|
227
|
+
|
|
228
|
+
content = " ".join(parts)
|
|
208
229
|
rendering_ctx.reset(token)
|
|
209
230
|
|
|
210
231
|
# XSS protection: escape content
|
|
@@ -216,48 +237,71 @@ class TextWidgetsMixin:
|
|
|
216
237
|
return Component("div", id=cid, content=html_output)
|
|
217
238
|
self._register_component(cid, builder)
|
|
218
239
|
|
|
219
|
-
def title(self,
|
|
240
|
+
def title(self, *args):
|
|
220
241
|
"""Display title (h1 with gradient)"""
|
|
221
|
-
self.heading(
|
|
242
|
+
self.heading(*args, level=1, divider=False)
|
|
222
243
|
|
|
223
|
-
def header(self,
|
|
244
|
+
def header(self, *args, divider: bool = True):
|
|
224
245
|
"""Display header (h2)"""
|
|
225
|
-
self.heading(
|
|
246
|
+
self.heading(*args, level=2, divider=divider)
|
|
226
247
|
|
|
227
|
-
def subheader(self,
|
|
248
|
+
def subheader(self, *args, divider: bool = False):
|
|
228
249
|
"""Display subheader (h3)"""
|
|
229
|
-
self.heading(
|
|
250
|
+
self.heading(*args, level=3, divider=divider)
|
|
230
251
|
|
|
231
|
-
def text(self,
|
|
232
|
-
"""Display text paragraph
|
|
233
|
-
|
|
252
|
+
def text(self, *args, size: str = "medium", muted: bool = False):
|
|
253
|
+
"""Display text paragraph
|
|
254
|
+
|
|
255
|
+
Supports multiple arguments which will be joined by spaces.
|
|
256
|
+
"""
|
|
257
|
+
from ..state import State, ComputedState
|
|
234
258
|
|
|
235
259
|
cid = self._get_next_cid("text")
|
|
236
260
|
def builder():
|
|
237
261
|
token = rendering_ctx.set(cid)
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
262
|
+
|
|
263
|
+
parts = []
|
|
264
|
+
for arg in args:
|
|
265
|
+
if isinstance(arg, (State, ComputedState)):
|
|
266
|
+
parts.append(str(arg.value))
|
|
267
|
+
elif callable(arg):
|
|
268
|
+
parts.append(str(arg()))
|
|
269
|
+
else:
|
|
270
|
+
parts.append(str(arg))
|
|
271
|
+
|
|
272
|
+
val = " ".join(parts)
|
|
244
273
|
rendering_ctx.reset(token)
|
|
274
|
+
|
|
245
275
|
cls = f"text-{size} {'text-muted' if muted else ''}"
|
|
246
276
|
# XSS protection: enable content escaping
|
|
247
277
|
return Component("p", id=cid, content=val, escape_content=True, class_=cls)
|
|
248
278
|
self._register_component(cid, builder)
|
|
249
279
|
|
|
250
|
-
def caption(self,
|
|
280
|
+
def caption(self, *args):
|
|
251
281
|
"""Display caption text (small, muted)"""
|
|
252
|
-
self.text(
|
|
282
|
+
self.text(*args, size="small", muted=True)
|
|
253
283
|
|
|
254
|
-
def markdown(self,
|
|
255
|
-
"""Display markdown-formatted text
|
|
284
|
+
def markdown(self, *args, **props):
|
|
285
|
+
"""Display markdown-formatted text
|
|
286
|
+
|
|
287
|
+
Supports multiple arguments which will be joined by spaces.
|
|
288
|
+
"""
|
|
256
289
|
cid = self._get_next_cid("markdown")
|
|
257
290
|
def builder():
|
|
258
291
|
token = rendering_ctx.set(cid)
|
|
259
|
-
|
|
292
|
+
from ..state import State, ComputedState
|
|
293
|
+
|
|
294
|
+
parts = []
|
|
295
|
+
for arg in args:
|
|
296
|
+
if isinstance(arg, (State, ComputedState)):
|
|
297
|
+
parts.append(str(arg.value))
|
|
298
|
+
elif callable(arg):
|
|
299
|
+
parts.append(str(arg()))
|
|
300
|
+
else:
|
|
301
|
+
parts.append(str(arg))
|
|
260
302
|
|
|
303
|
+
content = " ".join(parts)
|
|
304
|
+
|
|
261
305
|
# Enhanced markdown conversion - line-by-line processing
|
|
262
306
|
import re
|
|
263
307
|
lines = content.split('\n')
|
|
@@ -332,19 +376,30 @@ class TextWidgetsMixin:
|
|
|
332
376
|
return Component("div", id=cid, content=html, class_="markdown", **props)
|
|
333
377
|
self._register_component(cid, builder)
|
|
334
378
|
|
|
335
|
-
def html(self,
|
|
379
|
+
def html(self, *args, **props):
|
|
336
380
|
"""Display raw HTML content
|
|
337
381
|
|
|
338
382
|
Use this when you need to render HTML directly without markdown processing.
|
|
339
383
|
For markdown formatting, use app.markdown() instead.
|
|
340
384
|
|
|
341
385
|
Example:
|
|
342
|
-
app.html('<div class="custom">
|
|
386
|
+
app.html('<div class="custom">', count, '</div>')
|
|
343
387
|
"""
|
|
344
388
|
cid = self._get_next_cid("html")
|
|
345
389
|
def builder():
|
|
390
|
+
from ..state import State, ComputedState
|
|
346
391
|
token = rendering_ctx.set(cid)
|
|
347
|
-
|
|
392
|
+
|
|
393
|
+
parts = []
|
|
394
|
+
for arg in args:
|
|
395
|
+
if isinstance(arg, (State, ComputedState)):
|
|
396
|
+
parts.append(str(arg.value))
|
|
397
|
+
elif callable(arg):
|
|
398
|
+
parts.append(str(arg()))
|
|
399
|
+
else:
|
|
400
|
+
parts.append(str(arg))
|
|
401
|
+
|
|
402
|
+
content = " ".join(parts)
|
|
348
403
|
rendering_ctx.reset(token)
|
|
349
404
|
return Component("div", id=cid, content=content, **props)
|
|
350
405
|
self._register_component(cid, builder)
|
|
@@ -371,16 +426,6 @@ class TextWidgetsMixin:
|
|
|
371
426
|
return Component("div", id=cid, content=html_output, **props)
|
|
372
427
|
self._register_component(cid, builder)
|
|
373
428
|
|
|
374
|
-
def html(self, html_content: Union[str, Callable], **props):
|
|
375
|
-
"""Render raw HTML"""
|
|
376
|
-
cid = self._get_next_cid("html")
|
|
377
|
-
def builder():
|
|
378
|
-
token = rendering_ctx.set(cid)
|
|
379
|
-
content = html_content() if callable(html_content) else html_content
|
|
380
|
-
rendering_ctx.reset(token)
|
|
381
|
-
return Component("div", id=cid, content=content, **props)
|
|
382
|
-
self._register_component(cid, builder)
|
|
383
|
-
|
|
384
429
|
def divider(self):
|
|
385
430
|
"""Display horizontal divider"""
|
|
386
431
|
cid = self._get_next_cid("divider")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: violit
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.6
|
|
4
4
|
Summary: Violit: Faster than Light, Beautiful as Violet. The High-Performance Python Web Framework (Streamlit Alternative with Zero Rerun).
|
|
5
5
|
Author-email: Violit Team <violit.company@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -2,25 +2,25 @@ violit/__init__.py,sha256=mD8FeVW-LQ8yLpW2Unc-K885T507BgRfSI7mmObpPK0,88
|
|
|
2
2
|
violit/app.py,sha256=G_li1AU8vH25T1VryG6kb7jrYV_zUucBdbg_goA_Q98,102272
|
|
3
3
|
violit/broadcast.py,sha256=IIRQR15Wr7cqHh0nSH86QdWN_Wd_GHNfVrtWCATGElc,24293
|
|
4
4
|
violit/broadcast_primitives.py,sha256=G4Nx9BZscidPAjUc9janwIJ0zUi6DAnNFeJS67Uvs9I,5739
|
|
5
|
-
violit/component.py,sha256=
|
|
5
|
+
violit/component.py,sha256=HBh72unqjNUri05UAK_TnQVsPJULot2hgAQK8HKqQLM,1483
|
|
6
6
|
violit/context.py,sha256=oai3FiBFwZbAK-ONHCPzItITHjXeZ3zXNya_BmPlX8I,517
|
|
7
7
|
violit/engine.py,sha256=oH3C04vhVgZFgy0HSaI9vPOkBEZBQBz40zs1Y1my9vw,1829
|
|
8
|
-
violit/state.py,sha256=
|
|
8
|
+
violit/state.py,sha256=oxIVCa-nencMjQXAs9ZMwfeTuz4w0LAeKDvBv_lvzhQ,12721
|
|
9
9
|
violit/theme.py,sha256=1Ht2DariRADxGU1GTtUFJaIXZXi9XuhnucT2d04cwhs,30781
|
|
10
10
|
violit/widgets/__init__.py,sha256=DdNdPahOIxEGKnV-MP-amA3jKGnE8GCUxKrtKN2sR9o,877
|
|
11
11
|
violit/widgets/card_widgets.py,sha256=rRGuY-7pArbneILQ8cLkBgiE820S6RCe1a2EZq0ZA3k,23112
|
|
12
|
-
violit/widgets/chart_widgets.py,sha256=
|
|
12
|
+
violit/widgets/chart_widgets.py,sha256=WtPRunw_2t45RTPtIHuvEkBd8miTJUL6HOYlVlvHE9k,10681
|
|
13
13
|
violit/widgets/chat_widgets.py,sha256=YHNY4SDqHJhTi3Lq_5lGl01y9jsJAfbPlH4Ar0UqYC8,10899
|
|
14
|
-
violit/widgets/data_widgets.py,sha256=
|
|
14
|
+
violit/widgets/data_widgets.py,sha256=NhQnQ_FAD2ey4mXUxaPT67rzjen-BLKU7pZSPmcln5Y,23431
|
|
15
15
|
violit/widgets/form_widgets.py,sha256=QVj-MRVpYzIM3hE8ISS5xZcX3jlTTzjRYSdzhw-K5OY,18327
|
|
16
|
-
violit/widgets/input_widgets.py,sha256=
|
|
16
|
+
violit/widgets/input_widgets.py,sha256=FjuSzNg00PnoQFyQDt6b6pWWrqofVcQeHHJX4L42voU,32768
|
|
17
17
|
violit/widgets/layout_widgets.py,sha256=--2vxZAxVfPCrLz74OBE5RM4x1RoOfMR3w1w79kXUFg,17606
|
|
18
18
|
violit/widgets/list_widgets.py,sha256=2-FWluNGfdBBN24ZyHOC2a8O93-NzGYHZlVYARX4FpI,3836
|
|
19
19
|
violit/widgets/media_widgets.py,sha256=FIMjaE1CIfqnsdMHbbCromjwxoWPfvFKmL0_qd6nDL4,7386
|
|
20
|
-
violit/widgets/status_widgets.py,sha256=
|
|
21
|
-
violit/widgets/text_widgets.py,sha256=
|
|
22
|
-
violit-0.0.
|
|
23
|
-
violit-0.0.
|
|
24
|
-
violit-0.0.
|
|
25
|
-
violit-0.0.
|
|
26
|
-
violit-0.0.
|
|
20
|
+
violit/widgets/status_widgets.py,sha256=ImA8vunM2Vk30-eECyl0eGiN75Nj7qtciwHgwgrymAs,13447
|
|
21
|
+
violit/widgets/text_widgets.py,sha256=yFlcDrJYTQTB25X562xiVZWS0Lz3-tljFxJcGRtAlb4,17867
|
|
22
|
+
violit-0.0.6.dist-info/licenses/LICENSE,sha256=dMxDVLF-GU5ZhQ-GmpL_eY4j7Wn1c4CtmRU8cOnR7Hw,1093
|
|
23
|
+
violit-0.0.6.dist-info/METADATA,sha256=nh6AXUz9720pCMLFxxYNjwITb2rD5_4PDQGxHXtAY2o,12599
|
|
24
|
+
violit-0.0.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
25
|
+
violit-0.0.6.dist-info/top_level.txt,sha256=VormCSpHvTyMyZQ17MwgiPegDJev8HQCN5HUUcxUcE0,7
|
|
26
|
+
violit-0.0.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|