dars-framework 1.2.3__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 (118) hide show
  1. dars/__init__.py +0 -0
  2. dars/all.py +69 -0
  3. dars/cli/__init__.py +0 -0
  4. dars/cli/doctor/__init__.py +1 -0
  5. dars/cli/doctor/detect.py +154 -0
  6. dars/cli/doctor/doctor.py +176 -0
  7. dars/cli/doctor/installers.py +100 -0
  8. dars/cli/doctor/persist.py +62 -0
  9. dars/cli/doctor/preflight.py +33 -0
  10. dars/cli/doctor/ui.py +54 -0
  11. dars/cli/hot_reload.py +33 -0
  12. dars/cli/main.py +1107 -0
  13. dars/cli/preview.py +448 -0
  14. dars/cli/translations.py +531 -0
  15. dars/components/__init__.py +0 -0
  16. dars/components/advanced/__init__.py +8 -0
  17. dars/components/advanced/accordion.py +26 -0
  18. dars/components/advanced/card.py +33 -0
  19. dars/components/advanced/modal.py +45 -0
  20. dars/components/advanced/navbar.py +44 -0
  21. dars/components/advanced/table.py +25 -0
  22. dars/components/advanced/tabs.py +31 -0
  23. dars/components/basic/__init__.py +34 -0
  24. dars/components/basic/button.py +55 -0
  25. dars/components/basic/checkbox.py +35 -0
  26. dars/components/basic/container.py +29 -0
  27. dars/components/basic/datepicker.py +139 -0
  28. dars/components/basic/image.py +36 -0
  29. dars/components/basic/input.py +57 -0
  30. dars/components/basic/link.py +31 -0
  31. dars/components/basic/markdown.py +86 -0
  32. dars/components/basic/page.py +20 -0
  33. dars/components/basic/progressbar.py +18 -0
  34. dars/components/basic/radiobutton.py +35 -0
  35. dars/components/basic/select.py +82 -0
  36. dars/components/basic/slider.py +63 -0
  37. dars/components/basic/spinner.py +12 -0
  38. dars/components/basic/text.py +23 -0
  39. dars/components/basic/textarea.py +46 -0
  40. dars/components/basic/tooltip.py +19 -0
  41. dars/components/layout/__init__.py +0 -0
  42. dars/components/layout/anchor.py +13 -0
  43. dars/components/layout/flex.py +26 -0
  44. dars/components/layout/grid.py +45 -0
  45. dars/config.py +134 -0
  46. dars/core/__init__.py +0 -0
  47. dars/core/app.py +957 -0
  48. dars/core/component.py +284 -0
  49. dars/core/events.py +102 -0
  50. dars/core/js_bridge.py +99 -0
  51. dars/core/properties.py +127 -0
  52. dars/core/state.py +309 -0
  53. dars/dars_tests/apps_test/health_check.py +56 -0
  54. dars/dars_tests/run_tests.py +275 -0
  55. dars/dars_tests/tests/test_advanced_components.py +69 -0
  56. dars/dars_tests/tests/test_basic_components.py +88 -0
  57. dars/dars_tests/tests/test_core_and_cli.py +17 -0
  58. dars/dars_tests/tests/test_layout_components.py +58 -0
  59. dars/dars_tests/tests/test_version_check.py +21 -0
  60. dars/docs/__init__.py +0 -0
  61. dars/docs/app.md +290 -0
  62. dars/docs/cli.md +80 -0
  63. dars/docs/components.md +1679 -0
  64. dars/docs/custom_components.md +30 -0
  65. dars/docs/events.md +45 -0
  66. dars/docs/exporters.md +162 -0
  67. dars/docs/getting_started.md +79 -0
  68. dars/docs/index.md +18 -0
  69. dars/docs/scripts.md +593 -0
  70. dars/docs/state_management.md +57 -0
  71. dars/exporters/__init__.py +0 -0
  72. dars/exporters/base.py +96 -0
  73. dars/exporters/web/OLD/html_css_js_OLD4.py +1538 -0
  74. dars/exporters/web/OLD/html_css_js_old.py +1406 -0
  75. dars/exporters/web/OLD/html_css_js_old2.py +1406 -0
  76. dars/exporters/web/__init__.py +0 -0
  77. dars/exporters/web/html_css_js.py +2675 -0
  78. dars/exporters/web/vdom.py +251 -0
  79. dars/js_lib.py +206 -0
  80. dars/scripts/__init__.py +0 -0
  81. dars/scripts/dscript.py +26 -0
  82. dars/scripts/script.py +39 -0
  83. dars/security.py +195 -0
  84. dars/templates/__init__.py +0 -0
  85. dars/templates/__pycache__/__init__.cpython-311.pyc +0 -0
  86. dars/templates/examples/README.md +4 -0
  87. dars/templates/examples/__pycache__/dynamic_event_demo.cpython-311.pyc +0 -0
  88. dars/templates/examples/advanced/Modal_Demo/advanced_modal_demo.py +275 -0
  89. dars/templates/examples/advanced/SimpleDashboard/dashboard.py +437 -0
  90. dars/templates/examples/advanced/SimpleModermWeb/modern_web_app.py +452 -0
  91. dars/templates/examples/advanced/VariousComponents/all_components_demo.py +87 -0
  92. dars/templates/examples/advanced/__init__.py +0 -0
  93. dars/templates/examples/advanced/dState/state_mods_demo.py +68 -0
  94. dars/templates/examples/basic/Forms/form_components.py +516 -0
  95. dars/templates/examples/basic/Forms/simple_form.py +379 -0
  96. dars/templates/examples/basic/HelloWorld/hello_world.py +56 -0
  97. dars/templates/examples/basic/Layouts/flex_layout_responsive.py +13 -0
  98. dars/templates/examples/basic/Layouts/grid_layout_responsive.py +12 -0
  99. dars/templates/examples/basic/Layouts/layout_multipage_demo.py +23 -0
  100. dars/templates/examples/basic/Multipage/multipage_example.py +67 -0
  101. dars/templates/examples/basic/PWA/icon-192x192.png +0 -0
  102. dars/templates/examples/basic/PWA/icon-512x512.png +0 -0
  103. dars/templates/examples/basic/PWA/pwa_custom_icons.py +33 -0
  104. dars/templates/examples/basic/__init__.py +0 -0
  105. dars/templates/examples/demo/__pycache__/complete_app.cpython-311.pyc +0 -0
  106. dars/templates/examples/demo/complete_app.py +21 -0
  107. dars/templates/examples/markdown/MarkdownTemplate/README.md +159 -0
  108. dars/templates/examples/markdown/MarkdownTemplate/markdown_template.py +21 -0
  109. dars/templates/examples/markdown/MarkdownTemplate/other_docs.md +1 -0
  110. dars/templates/examples/markdown/__init__.py +0 -0
  111. dars/templates/html/__init__.py +0 -0
  112. dars/version.py +2 -0
  113. dars_framework-1.2.3.dist-info/METADATA +15 -0
  114. dars_framework-1.2.3.dist-info/RECORD +118 -0
  115. dars_framework-1.2.3.dist-info/WHEEL +5 -0
  116. dars_framework-1.2.3.dist-info/entry_points.txt +2 -0
  117. dars_framework-1.2.3.dist-info/licenses/LICENSE +21 -0
  118. dars_framework-1.2.3.dist-info/top_level.txt +1 -0
dars/cli/preview.py ADDED
@@ -0,0 +1,448 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Dars Preview - Preview system for exported applications
4
+ """
5
+
6
+ import os
7
+ import sys
8
+ import webbrowser
9
+ import http.server
10
+ import mimetypes
11
+ import socketserver
12
+ import threading
13
+ import time
14
+ from pathlib import Path
15
+
16
+ from rich.console import Console
17
+ from rich.panel import Panel
18
+ from rich.text import Text
19
+ from rich.table import Table
20
+ from rich import print as rprint
21
+
22
+ from dars.cli.translations import translator
23
+
24
+ console = Console()
25
+
26
+ class PreviewServer:
27
+ """Preview server for Dars applications"""
28
+
29
+ class DarsRequestHandler(http.server.SimpleHTTPRequestHandler):
30
+ def end_headers(self):
31
+ # CORS para desarrollo PWA si es necesario
32
+ self.send_header('Access-Control-Allow-Origin', '*')
33
+ super().end_headers()
34
+ def guess_type(self, path):
35
+ # Ensure correct MIME types for JS modules and JSON
36
+ if path.endswith('.mjs') or path.endswith('.js'):
37
+ return 'application/javascript'
38
+ if path.endswith('.json'):
39
+ return 'application/json'
40
+ return super().guess_type(path)
41
+ def log_request(self, code='-', size='-'):
42
+ """Silencia logs para peticiones frecuentes del hot-reload (version.txt)."""
43
+ try:
44
+ p = getattr(self, 'path', '') or ''
45
+ # Coincidir /version.txt o /version_<slug>.txt
46
+ if p.endswith('version.txt') or (p.startswith('/version_') and p.endswith('.txt')):
47
+ return # no loggear
48
+ except Exception:
49
+ pass
50
+ return super().log_request(code, size)
51
+
52
+ def __init__(self, directory: str, port: int = 8000):
53
+ self.directory = os.path.abspath(directory)
54
+ self.port = port
55
+ self.server = None
56
+ self.server_thread = None
57
+
58
+ def start(self):
59
+ """Starts the preview server"""
60
+ try:
61
+ # Change to the application directory
62
+ os.chdir(self.directory)
63
+
64
+ # Create the server
65
+ # Register mimetypes for strict module loading
66
+ try:
67
+ mimetypes.add_type('application/javascript', '.js')
68
+ mimetypes.add_type('application/javascript', '.mjs')
69
+ mimetypes.add_type('application/json', '.json')
70
+ except Exception:
71
+ pass
72
+ handler = self.DarsRequestHandler
73
+ self.server = socketserver.TCPServer(("", self.port), handler)
74
+
75
+ # Start in a separate thread
76
+ self.server_thread = threading.Thread(target=self.server.serve_forever)
77
+ self.server_thread.daemon = True
78
+ self.server_thread.start()
79
+
80
+ return True
81
+
82
+ except Exception as e:
83
+ console.print(f"[red]{translator.get('server_start_error')}: {e}[/red]")
84
+ return False
85
+
86
+ def stop(self):
87
+ """Stops the preview server"""
88
+ if self.server:
89
+ self.server.shutdown()
90
+ self.server.server_close()
91
+
92
+ def get_url(self) -> str:
93
+ """Gets the server URL"""
94
+ return f"http://localhost:{self.port}"
95
+
96
+ def preview_html_app(directory: str, auto_open: bool = True, port: int = 8000):
97
+ """Previews an exported HTML application"""
98
+
99
+ import signal
100
+
101
+ # Verify that index.html exists
102
+ index_path = os.path.join(directory, "index.html")
103
+ if not os.path.exists(index_path):
104
+ console.print(f"[red]{translator.get('index_html_missing')} {directory}[/red]")
105
+ return False
106
+
107
+ # Create and start the server
108
+ server = PreviewServer(directory, port)
109
+
110
+ if not server.start():
111
+ return False
112
+
113
+ url = server.get_url()
114
+
115
+ # Show information
116
+ panel_content = f"""
117
+ [green]✓[/green] {translator.get('preview_server_started')}
118
+
119
+ [bold]URL:[/bold] {url}
120
+ [bold]{translator.get('directory')}:[/bold] {directory}
121
+ [bold]{translator.get('port')}:[/bold] {port}
122
+
123
+ [yellow]{translator.get('press_ctrl_c')}[/yellow]
124
+ """
125
+
126
+ console.print(Panel(panel_content, title="Dars Preview", border_style="green"))
127
+
128
+ # Open in browser if requested
129
+ if auto_open:
130
+ try:
131
+ webbrowser.open(url)
132
+ console.print(f"[cyan]{translator.get('opening_in_browser').format(url=url)}[/cyan]")
133
+ except Exception as e:
134
+ console.print(f"[yellow]{translator.get('browser_open_error')}: {e}[/yellow]")
135
+ console.print(f"[cyan]{translator.get('open_manually')}: {url}[/cyan]")
136
+
137
+ import threading
138
+ import signal
139
+
140
+ shutdown_event = threading.Event()
141
+
142
+ try:
143
+ while not shutdown_event.is_set():
144
+ shutdown_event.wait(timeout=1) # Espera hasta que se pida cerrar, sin consumir CPU
145
+ except KeyboardInterrupt:
146
+ shutdown_event.set()
147
+ finally:
148
+ console.print(f"\n[yellow]{translator.get('stopping_server')}[/yellow]")
149
+ server.stop()
150
+ console.print(f"[green]{translator.get('server_stopped')}[/green]")
151
+
152
+ return True
153
+
154
+ def preview_react_app(directory: str):
155
+ """Previews an exported React application"""
156
+
157
+ # Verify that package.json exists
158
+ package_path = os.path.join(directory, "package.json")
159
+ if not os.path.exists(package_path):
160
+ console.print(f"[red]{translator.get('package_json_not_found')} {directory}[/red]")
161
+ return False
162
+
163
+ console.print(Panel(
164
+ f"""
165
+ {translator.get('preview_react_instructions')}:
166
+
167
+ 1. {translator.get('navigate_to_directory')}:
168
+ [cyan]cd {directory}[/cyan]
169
+
170
+ 2. {translator.get('install_dependencies')}:
171
+ [cyan]npm install[/cyan]
172
+
173
+ 3. {translator.get('start_dev_server')}:
174
+ [cyan]npm start[/cyan]
175
+
176
+ {translator.get('app_will_open')} http://localhost:3000
177
+ """,
178
+ title=translator.get('react_preview'),
179
+ border_style="blue"
180
+ ))
181
+
182
+ return True
183
+
184
+ def preview_react_native_app(directory: str):
185
+ """Previews an exported React Native application"""
186
+
187
+ # Verify that package.json exists
188
+ package_path = os.path.join(directory, "package.json")
189
+ if not os.path.exists(package_path):
190
+ console.print(f"[red]{translator.get('package_json_not_found')} {directory}[/red]")
191
+ return False
192
+
193
+ console.print(Panel(
194
+ f"""
195
+ {translator.get('preview_react_native_instructions')}:
196
+
197
+ 1. {translator.get('navigate_to_directory')}:
198
+ [cyan]cd {directory}[/cyan]
199
+
200
+ 2. {translator.get('install_dependencies')}:
201
+ [cyan]npm install[/cyan]
202
+
203
+ 3. {translator.get('for_android')}:
204
+ [cyan]npm run android[/cyan]
205
+
206
+ 4. {translator.get('for_ios')}:
207
+ [cyan]npm run ios[/cyan]
208
+
209
+ 5. {translator.get('start_metro')}:
210
+ [cyan]npm start[/cyan]
211
+
212
+ [yellow]{translator.get('react_native_note')}[/yellow]
213
+ """,
214
+ title=translator.get('react_native_preview'),
215
+ border_style="green"
216
+ ))
217
+
218
+ return True
219
+
220
+ def preview_pyside6_app(directory: str):
221
+ """Previews an exported PySide6 application"""
222
+
223
+ # Verify that main.py exists
224
+ main_path = os.path.join(directory, "main.py")
225
+ if not os.path.exists(main_path):
226
+ console.print(f"[red]{translator.get('main_py_not_found')} {directory}[/red]")
227
+ return False
228
+
229
+ console.print(Panel(
230
+ f"""
231
+ {translator.get('run_pyside6_app')}:
232
+
233
+ 1. {translator.get('navigate_to_directory')}:
234
+ [cyan]cd {directory}[/cyan]
235
+
236
+ 2. {translator.get('install_dependencies')}:
237
+ [cyan]pip install -r requirements.txt[/cyan]
238
+
239
+ 3. {translator.get('run_application')}:
240
+ [cyan]python main.py[/cyan]
241
+
242
+ [yellow]{translator.get('pyside6_note')}[/yellow]
243
+ """,
244
+ title=translator.get('pyside6_preview'),
245
+ border_style="magenta"
246
+ ))
247
+
248
+ return True
249
+
250
+ def preview_csharp_app(directory: str):
251
+ """Previews an exported C# application"""
252
+
253
+ # Search for .csproj file
254
+ csproj_files = list(Path(directory).glob("*.csproj"))
255
+ if not csproj_files:
256
+ console.print(f"[red]{translator.get('csproj_not_found')} {directory}[/red]")
257
+ return False
258
+
259
+ csproj_file = csproj_files[0].name
260
+
261
+ console.print(Panel(
262
+ f"""
263
+ {translator.get('run_csharp_app')}:
264
+
265
+ 1. {translator.get('navigate_to_directory')}:
266
+ [cyan]cd {directory}[/cyan]
267
+
268
+ 2. {translator.get('restore_dependencies')}:
269
+ [cyan]dotnet restore[/cyan]
270
+
271
+ 3. {translator.get('build_application')}:
272
+ [cyan]dotnet build[/cyan]
273
+
274
+ 4. {translator.get('run_application')}:
275
+ [cyan]dotnet run[/cyan]
276
+
277
+ [yellow]{translator.get('dotnet_note')}[/yellow]
278
+ """,
279
+ title=translator.get('csharp_preview'),
280
+ border_style="red"
281
+ ))
282
+
283
+ return True
284
+
285
+ def preview_kotlin_app(directory: str):
286
+ """Previews an exported Kotlin application"""
287
+
288
+ # Verify that build.gradle.kts exists
289
+ gradle_path = os.path.join(directory, "build.gradle.kts")
290
+ if not os.path.exists(gradle_path):
291
+ console.print(f"[red]{translator.get('gradle_not_found')} {directory}[/red]")
292
+ return False
293
+
294
+ console.print(Panel(
295
+ f"""
296
+ {translator.get('run_kotlin_app')}:
297
+
298
+ 1. {translator.get('navigate_to_directory')}:
299
+ [cyan]cd {directory}[/cyan]
300
+
301
+ 2. {translator.get('for_desktop')}:
302
+ [cyan]./gradlew run[/cyan]
303
+
304
+ 3. {translator.get('for_android')}:
305
+ [cyan]./gradlew installDebug[/cyan]
306
+
307
+ 4. {translator.get('build_all_platforms')}:
308
+ [cyan]./gradlew build[/cyan]
309
+
310
+ [yellow]{translator.get('kotlin_note')}[/yellow]
311
+ """,
312
+ title=translator.get('kotlin_preview'),
313
+ border_style="yellow"
314
+ ))
315
+
316
+ return True
317
+
318
+ def auto_detect_format(directory: str) -> str:
319
+ """Automatically detects the format of the exported application"""
320
+
321
+ if os.path.exists(os.path.join(directory, "index.html")):
322
+ return "html"
323
+ elif os.path.exists(os.path.join(directory, "package.json")):
324
+ # Read package.json to distinguish between React and React Native
325
+ try:
326
+ import json
327
+ with open(os.path.join(directory, "package.json"), 'r') as f:
328
+ package_data = json.load(f)
329
+
330
+ if "react-native" in package_data.get("dependencies", {}):
331
+ return "react-native"
332
+ else:
333
+ return "react"
334
+ except:
335
+ return "react"
336
+ elif os.path.exists(os.path.join(directory, "main.py")):
337
+ return "pyside6"
338
+ elif list(Path(directory).glob("*.csproj")):
339
+ return "csharp"
340
+ elif os.path.exists(os.path.join(directory, "build.gradle.kts")):
341
+ return "kotlin"
342
+ else:
343
+ return "unknown"
344
+
345
+ def preview_app(directory: str, format_name: str = None, auto_open: bool = True, port: int = 8000):
346
+ """Previews an exported application"""
347
+
348
+ if not os.path.exists(directory):
349
+ console.print(f"[red]{translator.get('directory_not_exists').format(directory=directory)}[/red]")
350
+ return False
351
+
352
+ # Automatically detect format if not specified
353
+ if format_name is None:
354
+ format_name = auto_detect_format(directory)
355
+
356
+ if format_name == "unknown":
357
+ console.print(f"[red]{translator.get('format_not_detected').format(directory=directory)}[/red]")
358
+ return False
359
+
360
+ console.print(f"[cyan]{translator.get('detected_format')}: {format_name}[/cyan]")
361
+
362
+ # Call the corresponding previewer
363
+ preview_functions = {
364
+ "html": lambda: preview_html_app(directory, auto_open, port),
365
+ "react": lambda: preview_react_app(directory),
366
+ "react-native": lambda: preview_react_native_app(directory),
367
+ "pyside6": lambda: preview_pyside6_app(directory),
368
+ "csharp": lambda: preview_csharp_app(directory),
369
+ "kotlin": lambda: preview_kotlin_app(directory)
370
+ }
371
+
372
+ preview_function = preview_functions.get(format_name)
373
+ if preview_function:
374
+ return preview_function()
375
+ else:
376
+ console.print(f"[red]{translator.get('format_not_supported').format(format=format_name)}[/red]")
377
+ return False
378
+
379
+ if __name__ == "__main__":
380
+ import argparse
381
+ import sys
382
+
383
+ # First, create a simple parser just to extract the language
384
+ pre_parser = argparse.ArgumentParser(add_help=False)
385
+ pre_parser.add_argument("--lang", "-l", choices=["en", "es"], default="en")
386
+
387
+ # Parse known args to get language without triggering errors on other args
388
+ pre_args, _ = pre_parser.parse_known_args()
389
+
390
+ # Set language before creating the main parser and save preference if specified
391
+ # If --lang is in sys.argv, it means the user explicitly specified it
392
+ save_preference = "--lang" in sys.argv or "-l" in sys.argv
393
+ translator.set_language(pre_args.lang, save=save_preference)
394
+
395
+ # Check for help before parsing arguments to show Rich-styled help
396
+ if '-h' in sys.argv or '--help' in sys.argv:
397
+ # Show banner
398
+ console.print(Panel(
399
+ Text("Dars Preview", style="bold cyan", justify="center"),
400
+ subtitle=translator.get('preview_description'),
401
+ border_style="cyan"
402
+ ))
403
+
404
+ # Show usage
405
+ console.print(f"\n[bold cyan]{translator.get('usage')}:[/bold cyan]")
406
+ console.print("preview.py [-h] [--format FORMAT] [--no-open] [--port PORT] [--lang {en,es}] directory")
407
+
408
+ # Show positional arguments
409
+ console.print(f"\n[bold cyan]{translator.get('positional_arguments')}:[/bold cyan]")
410
+ pos_table = Table(show_header=False, box=None, padding=(0, 2, 0, 0), expand=True)
411
+ pos_table.add_column("Argument", style="bold green", width=20, no_wrap=True)
412
+ pos_table.add_column("Description", style="dim white", overflow="fold")
413
+ pos_table.add_row("directory", translator.get('directory_help'))
414
+ console.print(pos_table)
415
+
416
+ # Show options
417
+ console.print(f"\n[bold cyan]{translator.get('options')}:[/bold cyan]")
418
+ opt_table = Table(show_header=False, box=None, padding=(0, 2, 0, 0), expand=True)
419
+ opt_table.add_column("Option", style="bold green", width=30, no_wrap=True)
420
+ opt_table.add_column("Description", style="dim white", overflow="fold")
421
+ opt_table.add_row("-h, --help", "show this help message and exit")
422
+ opt_table.add_row("--format FORMAT, -f FORMAT", translator.get('format_help'))
423
+ opt_table.add_row("--no-open", translator.get('no_open_help'))
424
+ opt_table.add_row("--port PORT, -p PORT", translator.get('port_help'))
425
+ opt_table.add_row("--lang {en,es}, -l {en,es}", translator.get('lang_help'))
426
+ console.print(opt_table)
427
+
428
+ sys.exit(0)
429
+
430
+ # Now create the full parser with translated help text
431
+ parser = argparse.ArgumentParser(description=translator.get('preview_description'))
432
+ parser.add_argument("directory", help=translator.get('directory_help'))
433
+ parser.add_argument("--format", "-f", help=translator.get('format_help'))
434
+ parser.add_argument("--no-open", action="store_true", help=translator.get('no_open_help'))
435
+ parser.add_argument("--port", "-p", type=int, default=8000, help=translator.get('port_help'))
436
+ parser.add_argument("--lang", "-l", choices=["en", "es"], default="en", help=translator.get('lang_help'))
437
+
438
+ args = parser.parse_args()
439
+
440
+ success = preview_app(
441
+ args.directory,
442
+ args.format,
443
+ not args.no_open,
444
+ args.port
445
+ )
446
+
447
+ sys.exit(0 if success else 1)
448
+