dars-framework 1.1.2__tar.gz → 1.1.4__tar.gz
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.
- {dars_framework-1.1.2 → dars_framework-1.1.4}/MANIFEST.in +1 -1
- {dars_framework-1.1.2/dars_framework.egg-info → dars_framework-1.1.4}/PKG-INFO +7 -15
- {dars_framework-1.1.2 → dars_framework-1.1.4}/README.md +6 -14
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/cli/main.py +0 -1
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/cli/translations.py +4 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/core/app.py +9 -5
- dars_framework-1.1.4/dars/dars_tests/run_tests.py +262 -0
- dars_framework-1.1.4/dars/dars_tests/tests/test_advanced_components.py +69 -0
- dars_framework-1.1.4/dars/dars_tests/tests/test_basic_components.py +88 -0
- dars_framework-1.1.4/dars/dars_tests/tests/test_core_and_cli.py +17 -0
- dars_framework-1.1.4/dars/dars_tests/tests/test_layout_components.py +58 -0
- dars_framework-1.1.4/dars/dars_tests/tests/test_version_check.py +21 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/docs/app.md +112 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/docs/components.md +31 -30
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/docs/getting_started.md +1 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/docs/index.md +18 -16
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/exporters/web/html_css_js.py +28 -24
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/advanced/SimpleDashboard/dashboard.py +1 -4
- dars_framework-1.1.4/dars/templates/examples/advanced/SimpleModermWeb/modern_web_app.py +452 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/basic/HelloWorld/hello_world.py +1 -1
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/version.py +2 -2
- {dars_framework-1.1.2 → dars_framework-1.1.4/dars_framework.egg-info}/PKG-INFO +7 -15
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars_framework.egg-info/SOURCES.txt +7 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/pyproject.toml +1 -1
- {dars_framework-1.1.2 → dars_framework-1.1.4}/LICENSE +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/all.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/cli/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/cli/hot_reload.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/cli/preview.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/advanced/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/advanced/accordion.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/advanced/card.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/advanced/modal.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/advanced/navbar.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/advanced/table.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/advanced/tabs.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/button.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/checkbox.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/container.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/datepicker.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/image.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/input.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/link.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/markdown.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/page.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/progressbar.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/radiobutton.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/select.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/slider.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/spinner.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/text.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/textarea.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/basic/tooltip.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/layout/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/layout/anchor.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/layout/flex.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/components/layout/grid.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/core/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/core/component.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/core/events.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/core/properties.py +0 -0
- {dars_framework-1.1.2/dars/templates/examples/advanced/SimpleModermWeb → dars_framework-1.1.4/dars/dars_tests/apps_test}/modern_web_app.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/docs/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/docs/cli.md +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/docs/custom_components.md +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/docs/events.md +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/docs/exporters.md +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/docs/scripts.md +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/exporters/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/exporters/base.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/exporters/web/OLD/html_css_js_OLD4.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/exporters/web/OLD/html_css_js_old.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/exporters/web/OLD/html_css_js_old2.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/exporters/web/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/scripts/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/scripts/dscript.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/scripts/script.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/__pycache__/__init__.cpython-311.pyc +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/README.md +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/__pycache__/dynamic_event_demo.cpython-311.pyc +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/advanced/Modal_Demo/advanced_modal_demo.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/advanced/VariousComponents/all_components_demo.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/advanced/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/basic/Forms/form_components.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/basic/Forms/simple_form.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/basic/Layouts/flex_layout_responsive.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/basic/Layouts/grid_layout_responsive.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/basic/Layouts/layout_multipage_demo.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/basic/Multipage/multipage_example.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/basic/PWA/icon-192x192.png +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/basic/PWA/icon-512x512.png +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/basic/PWA/pwa_custom_icons.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/basic/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/demo/__pycache__/complete_app.cpython-311.pyc +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/demo/complete_app.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/markdown/MarkdownTemplate/README.md +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/markdown/MarkdownTemplate/markdown_template.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/markdown/MarkdownTemplate/other_docs.md +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/examples/markdown/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars/templates/html/__init__.py +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars_framework.egg-info/dependency_links.txt +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars_framework.egg-info/entry_points.txt +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars_framework.egg-info/requires.txt +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/dars_framework.egg-info/top_level.txt +0 -0
- {dars_framework-1.1.2 → dars_framework-1.1.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dars-framework
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.4
|
|
4
4
|
Summary: Dars is a Python UI framework for building modern, interactive web apps with only Python code. Write your interface in Python, export it to static HTML/CSS/JS, and deploy anywhere.
|
|
5
5
|
Author-email: ztamdev <zondax2009@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -51,10 +51,10 @@ Try dars without installing nothing just visit the [Dars Playground](https://dar
|
|
|
51
51
|
- Preview instantly with hot-reload using `app.rTimeCompile()`.
|
|
52
52
|
- Export your app to static web files with a single CLI command.
|
|
53
53
|
- Use multipage, layouts, scripts, and more—see docs for advanced features.
|
|
54
|
-
- For mor information visit the [Documentation](
|
|
54
|
+
- For mor information visit the [Documentation](https://ztamdev.github.io/Dars-Framework/documentation.html)
|
|
55
55
|
|
|
56
56
|
## Quick Example: Your First App
|
|
57
|
-
> Note: this is an single page example but you can build multipage apps with Page component see the [Components Documentation](
|
|
57
|
+
> Note: this is an single page example but you can build multipage apps with Page component see the [Components Documentation](https://ztamdev.github.io/Dars-Framework/documentation.html#dars-components-documentation) to know more.
|
|
58
58
|
|
|
59
59
|
```python
|
|
60
60
|
from dars import App, Container, Text, Button, InlineScript
|
|
@@ -109,18 +109,10 @@ if __name__ == "__main__":
|
|
|
109
109
|
| `dars --help` | Show help and all CLI options |
|
|
110
110
|
|
|
111
111
|
## More
|
|
112
|
-
|
|
113
|
-
- [
|
|
114
|
-
-
|
|
115
|
-
- [
|
|
116
|
-
- [Custom Components](dars/docs/custom_components.md)
|
|
117
|
-
- [Event Handling](dars/docs/events.md)
|
|
118
|
-
- [Exporters](dars/docs/exporters.md)
|
|
119
|
-
- [Scripts System](dars/docs/scripts.md)
|
|
120
|
-
- [CLI usage and commands](dars/docs/cli.md)
|
|
121
|
-
- [Project Structure](STRUCTURE.md)
|
|
122
|
-
- [Architecture](DARS_ARCHITECTURE.md)
|
|
123
|
-
- [Installation Guide](INSTALL.md)
|
|
112
|
+
|
|
113
|
+
- Visit dars [official website](https://ztamdev.github.io/Dars-Framework/)
|
|
114
|
+
- Visit the dars official [Documentation](https://ztamdev.github.io/Dars-Framework/documentation.html) now on separate website.
|
|
115
|
+
- Try dars without installing nothing just visit the [Dars Playground](https://dars-playground.vercel.app/)
|
|
124
116
|
|
|
125
117
|
## Local Execution and Live Preview
|
|
126
118
|
|
|
@@ -15,10 +15,10 @@ Try dars without installing nothing just visit the [Dars Playground](https://dar
|
|
|
15
15
|
- Preview instantly with hot-reload using `app.rTimeCompile()`.
|
|
16
16
|
- Export your app to static web files with a single CLI command.
|
|
17
17
|
- Use multipage, layouts, scripts, and more—see docs for advanced features.
|
|
18
|
-
- For mor information visit the [Documentation](
|
|
18
|
+
- For mor information visit the [Documentation](https://ztamdev.github.io/Dars-Framework/documentation.html)
|
|
19
19
|
|
|
20
20
|
## Quick Example: Your First App
|
|
21
|
-
> Note: this is an single page example but you can build multipage apps with Page component see the [Components Documentation](
|
|
21
|
+
> Note: this is an single page example but you can build multipage apps with Page component see the [Components Documentation](https://ztamdev.github.io/Dars-Framework/documentation.html#dars-components-documentation) to know more.
|
|
22
22
|
|
|
23
23
|
```python
|
|
24
24
|
from dars import App, Container, Text, Button, InlineScript
|
|
@@ -73,18 +73,10 @@ if __name__ == "__main__":
|
|
|
73
73
|
| `dars --help` | Show help and all CLI options |
|
|
74
74
|
|
|
75
75
|
## More
|
|
76
|
-
|
|
77
|
-
- [
|
|
78
|
-
-
|
|
79
|
-
- [
|
|
80
|
-
- [Custom Components](dars/docs/custom_components.md)
|
|
81
|
-
- [Event Handling](dars/docs/events.md)
|
|
82
|
-
- [Exporters](dars/docs/exporters.md)
|
|
83
|
-
- [Scripts System](dars/docs/scripts.md)
|
|
84
|
-
- [CLI usage and commands](dars/docs/cli.md)
|
|
85
|
-
- [Project Structure](STRUCTURE.md)
|
|
86
|
-
- [Architecture](DARS_ARCHITECTURE.md)
|
|
87
|
-
- [Installation Guide](INSTALL.md)
|
|
76
|
+
|
|
77
|
+
- Visit dars [official website](https://ztamdev.github.io/Dars-Framework/)
|
|
78
|
+
- Visit the dars official [Documentation](https://ztamdev.github.io/Dars-Framework/documentation.html) now on separate website.
|
|
79
|
+
- Try dars without installing nothing just visit the [Dars Playground](https://dars-playground.vercel.app/)
|
|
88
80
|
|
|
89
81
|
## Local Execution and Live Preview
|
|
90
82
|
|
|
@@ -368,7 +368,6 @@ class DarsExporter:
|
|
|
368
368
|
info_table.add_row(translator.get('scripts'), str(stats['scripts_count']))
|
|
369
369
|
info_table.add_row(translator.get('global_styles'), str(stats['global_styles_count']))
|
|
370
370
|
info_table.add_row(translator.get('theme'), app.config.get('theme', 'light'))
|
|
371
|
-
info_table.add_row(translator.get('responsive'), str(app.config.get('responsive', True)))
|
|
372
371
|
|
|
373
372
|
console.print(info_table)
|
|
374
373
|
|
|
@@ -17,6 +17,8 @@ translations = {
|
|
|
17
17
|
'info_help': "Show application information",
|
|
18
18
|
'formats_help': "Show supported formats",
|
|
19
19
|
'preview_help': "Preview information",
|
|
20
|
+
'property_column': "Property",
|
|
21
|
+
'value_column': "Value",
|
|
20
22
|
'preview_cmd_help': "Preview exported application",
|
|
21
23
|
'init_help': "Create a Dars project",
|
|
22
24
|
'template_not_found': "Template '{template}' not found",
|
|
@@ -171,6 +173,8 @@ translations = {
|
|
|
171
173
|
'preview_help': "Información de preview",
|
|
172
174
|
'preview_cmd_help': "Previsualizar aplicación exportada",
|
|
173
175
|
'init_help': "Crea un proyecto Dars",
|
|
176
|
+
'property_column': "Propiedad",
|
|
177
|
+
'value_column': "Valor",
|
|
174
178
|
|
|
175
179
|
# Export command
|
|
176
180
|
'file_help': "Archivo Python con la aplicación Dars",
|
|
@@ -127,7 +127,7 @@ class Page:
|
|
|
127
127
|
class App:
|
|
128
128
|
"""Main class that represents a Dars application"""
|
|
129
129
|
|
|
130
|
-
def rTimeCompile(self, exporter=None, port=None, add_file_types=".py, .js, .css"):
|
|
130
|
+
def rTimeCompile(self, exporter=None, port=None, add_file_types=".py, .js, .css", watchfiledialog=False):
|
|
131
131
|
"""
|
|
132
132
|
Generates a quick preview of the app on a local server using an exporter
|
|
133
133
|
(default: HTMLCSSJSExporter) and serving the files from a temporary directory.
|
|
@@ -145,6 +145,8 @@ class App:
|
|
|
145
145
|
import shutil
|
|
146
146
|
import traceback
|
|
147
147
|
|
|
148
|
+
self.watchfiledialog = watchfiledialog
|
|
149
|
+
|
|
148
150
|
@contextmanager
|
|
149
151
|
def pushd(path):
|
|
150
152
|
"""Cambia temporalmente el cwd y lo restaura al salir."""
|
|
@@ -425,11 +427,13 @@ class App:
|
|
|
425
427
|
subtitle=f"Project root: {os.path.basename(project_root)}",
|
|
426
428
|
border_style="magenta"
|
|
427
429
|
)
|
|
428
|
-
|
|
430
|
+
if self.watchfiledialog:
|
|
431
|
+
console.print(panel)
|
|
429
432
|
else:
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
+
if self.watchfiledialog:
|
|
434
|
+
print(f"[Dars] Watching {len(files_to_watch)} files in {project_root}:")
|
|
435
|
+
for f in files_to_watch:
|
|
436
|
+
print(" -", os.path.relpath(f, project_root))
|
|
433
437
|
|
|
434
438
|
# Loop principal: espera a Ctrl+C
|
|
435
439
|
while not shutdown_event.is_set():
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# Runner that executes the test files and prints a colored report using rich
|
|
2
|
+
import runpy, glob, importlib.util, os, sys, traceback, subprocess, time, threading
|
|
3
|
+
import requests
|
|
4
|
+
import signal
|
|
5
|
+
import webbrowser
|
|
6
|
+
import shutil
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
from rich.panel import Panel
|
|
10
|
+
from rich.prompt import Prompt
|
|
11
|
+
|
|
12
|
+
console = Console()
|
|
13
|
+
|
|
14
|
+
def run_unit_tests(unit_test_paths=None):
|
|
15
|
+
"""Run unit test files, optionally from specific paths"""
|
|
16
|
+
if unit_test_paths is None:
|
|
17
|
+
# Default behavior: run all tests in tests directory
|
|
18
|
+
tests = sorted(glob.glob(os.path.join(os.path.dirname(__file__), 'tests', 'test_*.py')))
|
|
19
|
+
else:
|
|
20
|
+
# Use provided test paths
|
|
21
|
+
tests = unit_test_paths
|
|
22
|
+
|
|
23
|
+
results = []
|
|
24
|
+
for t in tests:
|
|
25
|
+
name = os.path.basename(t)
|
|
26
|
+
try:
|
|
27
|
+
console.print(Panel(f'Running {name}', style='cyan'))
|
|
28
|
+
ns = runpy.run_path(t, run_name='__main__')
|
|
29
|
+
results.append((name, True, None))
|
|
30
|
+
console.print(f'[green]PASS[/green] {name}')
|
|
31
|
+
except Exception as e:
|
|
32
|
+
results.append((name, False, traceback.format_exc()))
|
|
33
|
+
console.print(f'[red]FAIL[/red] {name}')
|
|
34
|
+
console.print(traceback.format_exc())
|
|
35
|
+
return results
|
|
36
|
+
|
|
37
|
+
def check_server(port=8000, timeout=10):
|
|
38
|
+
"""Check if the server is running on the given port"""
|
|
39
|
+
start_time = time.time()
|
|
40
|
+
while time.time() - start_time < timeout:
|
|
41
|
+
try:
|
|
42
|
+
response = requests.get(f'http://localhost:{port}', timeout=2)
|
|
43
|
+
if response.status_code < 500:
|
|
44
|
+
return True
|
|
45
|
+
except requests.exceptions.RequestException:
|
|
46
|
+
time.sleep(0.5)
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
def run_app_with_timeout(app_file, timeout=15):
|
|
50
|
+
"""Run a Dars app with rTimeCompile and capture its output with a timeout"""
|
|
51
|
+
try:
|
|
52
|
+
# Redirigir stdout y stderr a archivos temporales o a devnull
|
|
53
|
+
with open(os.devnull, 'w') as devnull:
|
|
54
|
+
process = subprocess.Popen(
|
|
55
|
+
[sys.executable, app_file],
|
|
56
|
+
stdout=devnull, # Redirigir stdout a devnull
|
|
57
|
+
stderr=devnull, # Redirigir stderr a devnull
|
|
58
|
+
cwd=os.path.dirname(app_file),
|
|
59
|
+
env={**os.environ, 'PYTHONIOENCODING': 'utf-8'}, # Establecer codificación
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Esperar a que el servidor se inicie o timeout
|
|
63
|
+
server_started = False
|
|
64
|
+
start_time = time.time()
|
|
65
|
+
|
|
66
|
+
while time.time() - start_time < timeout:
|
|
67
|
+
if check_server(8000, 2):
|
|
68
|
+
server_started = True
|
|
69
|
+
break
|
|
70
|
+
time.sleep(1)
|
|
71
|
+
|
|
72
|
+
# Devolver resultados
|
|
73
|
+
return {
|
|
74
|
+
'success': server_started,
|
|
75
|
+
'process': process,
|
|
76
|
+
'stdout': '',
|
|
77
|
+
'stderr': ''
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
return {
|
|
82
|
+
'success': False,
|
|
83
|
+
'error': str(e),
|
|
84
|
+
'stdout': '',
|
|
85
|
+
'stderr': ''
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
def safe_read_file(file_path):
|
|
89
|
+
"""Leer un archivo de forma segura manejando diferentes codificaciones"""
|
|
90
|
+
encodings = ['utf-8', 'latin-1', 'cp1252', 'iso-8859-1']
|
|
91
|
+
|
|
92
|
+
for encoding in encodings:
|
|
93
|
+
try:
|
|
94
|
+
with open(file_path, 'r', encoding=encoding) as f:
|
|
95
|
+
return f.read()
|
|
96
|
+
except UnicodeDecodeError:
|
|
97
|
+
continue
|
|
98
|
+
|
|
99
|
+
# Si todas las codificaciones fallan, usar modo binario con reemplazo de errores
|
|
100
|
+
with open(file_path, 'rb') as f:
|
|
101
|
+
return f.read().decode('utf-8', errors='replace')
|
|
102
|
+
|
|
103
|
+
def run_app_tests(app_test_paths=None):
|
|
104
|
+
"""Run Dars application tests that use rTimeCompile, optionally from specific paths"""
|
|
105
|
+
if app_test_paths is None:
|
|
106
|
+
# Default behavior: run all apps in apps_test directory
|
|
107
|
+
apps_test_dir = os.path.join(os.path.dirname(__file__), 'apps_test')
|
|
108
|
+
if not os.path.exists(apps_test_dir):
|
|
109
|
+
console.print(f"[yellow]apps_test directory not found: {apps_test_dir}[/yellow]")
|
|
110
|
+
return []
|
|
111
|
+
|
|
112
|
+
apps = sorted(glob.glob(os.path.join(apps_test_dir, '*.py')))
|
|
113
|
+
else:
|
|
114
|
+
# Use provided app paths
|
|
115
|
+
apps = app_test_paths
|
|
116
|
+
|
|
117
|
+
results = []
|
|
118
|
+
|
|
119
|
+
for app_file in apps:
|
|
120
|
+
name = os.path.basename(app_file)
|
|
121
|
+
try:
|
|
122
|
+
console.print(Panel(f'Testing Dars App: {name}', style='magenta'))
|
|
123
|
+
|
|
124
|
+
# Verificar si la aplicación usa rTimeCompile de forma segura
|
|
125
|
+
content = safe_read_file(app_file)
|
|
126
|
+
uses_rTimeCompile = 'rTimeCompile' in content
|
|
127
|
+
|
|
128
|
+
if not uses_rTimeCompile:
|
|
129
|
+
console.print(f"[yellow]Skipping {name} - does not use rTimeCompile[/yellow]")
|
|
130
|
+
continue
|
|
131
|
+
|
|
132
|
+
# Ejecutar la aplicación con timeout
|
|
133
|
+
result = run_app_with_timeout(app_file, timeout=20)
|
|
134
|
+
|
|
135
|
+
if result['success']:
|
|
136
|
+
# Éxito: el servidor se inició correctamente
|
|
137
|
+
results.append((name, True, "App started server successfully on port 8000"))
|
|
138
|
+
console.print(f'[green]PASS[/green] {name}')
|
|
139
|
+
|
|
140
|
+
# Abrir el navegador para verificación visual
|
|
141
|
+
console.print("[green]Opening browser for visual verification...[/green]")
|
|
142
|
+
webbrowser.open('http://localhost:8000')
|
|
143
|
+
|
|
144
|
+
# Preguntar al usuario si quiere terminar el proceso
|
|
145
|
+
console.print("\n[bold]Please verify the application in your browser.[/bold]")
|
|
146
|
+
console.print("After verification, you can:")
|
|
147
|
+
console.print("1. Press 'y' to terminate the process and continue with tests")
|
|
148
|
+
console.print("2. Press 'n' to keep the server running and continue")
|
|
149
|
+
|
|
150
|
+
response = Prompt.ask("\nTerminate process and continue?", choices=["y", "n"], default="y")
|
|
151
|
+
|
|
152
|
+
if response.lower() == "y":
|
|
153
|
+
# Terminar el proceso
|
|
154
|
+
if 'process' in result and result['process'].poll() is None:
|
|
155
|
+
console.print("[yellow]Terminating app process...[/yellow]")
|
|
156
|
+
try:
|
|
157
|
+
# Enviar señal de interrupción (equivalente a Ctrl+C)
|
|
158
|
+
if os.name == 'nt': # Windows
|
|
159
|
+
result['process'].terminate()
|
|
160
|
+
else: # Unix
|
|
161
|
+
result['process'].send_signal(signal.SIGINT)
|
|
162
|
+
|
|
163
|
+
# Esperar a que termine
|
|
164
|
+
result['process'].wait(timeout=10)
|
|
165
|
+
console.print("[green]App process terminated successfully[/green]")
|
|
166
|
+
|
|
167
|
+
# Limpiar carpeta dars_preview
|
|
168
|
+
preview_dir = os.path.join(os.path.dirname(app_file), "dars_preview")
|
|
169
|
+
if os.path.exists(preview_dir):
|
|
170
|
+
shutil.rmtree(preview_dir)
|
|
171
|
+
console.print("[green]Preview directory cleaned up[/green]")
|
|
172
|
+
|
|
173
|
+
except:
|
|
174
|
+
console.print("[red]Force killing app process...[/red]")
|
|
175
|
+
result['process'].kill()
|
|
176
|
+
else:
|
|
177
|
+
console.print("[yellow]Keeping server running...[/yellow]")
|
|
178
|
+
else:
|
|
179
|
+
# Fallo: el servidor no se inició
|
|
180
|
+
error_msg = result['stderr'] or result['stdout'] or "Unknown error"
|
|
181
|
+
results.append((name, False, error_msg))
|
|
182
|
+
console.print(f'[red]FAIL[/red] {name}: {error_msg}')
|
|
183
|
+
|
|
184
|
+
# Terminar el proceso si todavía está ejecutándose (solo si no elegimos mantenerlo)
|
|
185
|
+
if 'process' in result and result['process'].poll() is None:
|
|
186
|
+
console.print("[yellow]Terminating app process...[/yellow]")
|
|
187
|
+
try:
|
|
188
|
+
# Enviar señal de interrupción (equivalente a Ctrl+C)
|
|
189
|
+
if os.name == 'nt': # Windows
|
|
190
|
+
result['process'].terminate()
|
|
191
|
+
else: # Unix
|
|
192
|
+
result['process'].send_signal(signal.SIGINT)
|
|
193
|
+
|
|
194
|
+
# Esperar a que termine
|
|
195
|
+
result['process'].wait(timeout=10)
|
|
196
|
+
console.print("[green]App process terminated successfully[/green]")
|
|
197
|
+
|
|
198
|
+
# Limpiar carpeta dars_preview
|
|
199
|
+
preview_dir = os.path.join(os.path.dirname(app_file), "dars_preview")
|
|
200
|
+
if os.path.exists(preview_dir):
|
|
201
|
+
shutil.rmtree(preview_dir)
|
|
202
|
+
console.print("[green]Preview directory cleaned up[/green]")
|
|
203
|
+
|
|
204
|
+
except:
|
|
205
|
+
console.print("[red]Force killing app process...[/red]")
|
|
206
|
+
result['process'].kill()
|
|
207
|
+
|
|
208
|
+
except Exception as e:
|
|
209
|
+
results.append((name, False, str(e)))
|
|
210
|
+
console.print(f'[red]FAIL[/red] {name}: {e}')
|
|
211
|
+
|
|
212
|
+
return results
|
|
213
|
+
|
|
214
|
+
def main(unit_test_paths=None, app_test_paths=None):
|
|
215
|
+
"""
|
|
216
|
+
Run Dars test suite with optional specific test paths
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
unit_test_paths (list): Optional list of paths to unit test files
|
|
220
|
+
app_test_paths (list): Optional list of paths to application test files
|
|
221
|
+
"""
|
|
222
|
+
# Run unit tests
|
|
223
|
+
console.print(Panel("Running Unit Tests", style="cyan"))
|
|
224
|
+
unit_results = run_unit_tests(unit_test_paths)
|
|
225
|
+
|
|
226
|
+
# Run app tests
|
|
227
|
+
console.print(Panel("Running App Tests (rTimeCompile)", style="magenta"))
|
|
228
|
+
app_results = run_app_tests(app_test_paths)
|
|
229
|
+
|
|
230
|
+
# Combine results
|
|
231
|
+
all_results = unit_results + app_results
|
|
232
|
+
|
|
233
|
+
# Print results table
|
|
234
|
+
table = Table(title='Dars Test Suite Results')
|
|
235
|
+
table.add_column('Test File')
|
|
236
|
+
table.add_column('Result')
|
|
237
|
+
table.add_column('Details', overflow='fold')
|
|
238
|
+
|
|
239
|
+
for name, ok, details in all_results:
|
|
240
|
+
table.add_row(name, '[green]PASS[/green]' if ok else '[red]FAIL[/red]', details or '')
|
|
241
|
+
|
|
242
|
+
console.print(table)
|
|
243
|
+
|
|
244
|
+
# Exit code
|
|
245
|
+
any_fail = any(not ok for _, ok, _ in all_results)
|
|
246
|
+
if any_fail:
|
|
247
|
+
console.print('[bold red]Some tests failed.[/bold red]')
|
|
248
|
+
sys.exit(1)
|
|
249
|
+
else:
|
|
250
|
+
console.print('[bold green]All tests passed.[/bold green]')
|
|
251
|
+
|
|
252
|
+
if __name__ == '__main__':
|
|
253
|
+
# Parse command line arguments for custom test paths
|
|
254
|
+
import argparse
|
|
255
|
+
parser = argparse.ArgumentParser(description='Run Dars Framework tests')
|
|
256
|
+
parser.add_argument('--unit-tests', nargs='+', help='Paths to specific unit test files')
|
|
257
|
+
parser.add_argument('--app-tests', nargs='+', help='Paths to specific application test files')
|
|
258
|
+
|
|
259
|
+
args = parser.parse_args()
|
|
260
|
+
|
|
261
|
+
# Run tests with optional paths
|
|
262
|
+
main(unit_test_paths=args.unit_tests, app_test_paths=args.app_tests)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import importlib, inspect, sys, os
|
|
2
|
+
from dars.core.component import Component
|
|
3
|
+
from dars.components.basic.text import Text
|
|
4
|
+
|
|
5
|
+
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'dars'))
|
|
6
|
+
if project_root not in sys.path:
|
|
7
|
+
sys.path.insert(0, project_root)
|
|
8
|
+
|
|
9
|
+
failures = []
|
|
10
|
+
|
|
11
|
+
def test_advanced_components():
|
|
12
|
+
base_pkg = 'dars.components.advanced'
|
|
13
|
+
try:
|
|
14
|
+
pkg = importlib.import_module(base_pkg)
|
|
15
|
+
except Exception as e:
|
|
16
|
+
raise AssertionError(f'Could not import {base_pkg}: {e}')
|
|
17
|
+
|
|
18
|
+
pkg_path = os.path.dirname(pkg.__file__)
|
|
19
|
+
for fname in os.listdir(pkg_path):
|
|
20
|
+
if not fname.endswith('.py') or fname.startswith('__'):
|
|
21
|
+
continue
|
|
22
|
+
|
|
23
|
+
modname = f"{base_pkg}.{fname[:-3]}"
|
|
24
|
+
try:
|
|
25
|
+
m = importlib.import_module(modname)
|
|
26
|
+
except Exception as e:
|
|
27
|
+
failures.append((modname, 'import', repr(e)))
|
|
28
|
+
continue
|
|
29
|
+
|
|
30
|
+
for _name, obj in inspect.getmembers(m, inspect.isclass):
|
|
31
|
+
try:
|
|
32
|
+
if obj is Component:
|
|
33
|
+
continue
|
|
34
|
+
if issubclass(obj, Component):
|
|
35
|
+
# Proporciona argumentos específicos para cada componente avanzado
|
|
36
|
+
if _name == 'Accordion':
|
|
37
|
+
instance = obj(sections=[{'title': 'Test', 'content': 'Content'}])
|
|
38
|
+
elif _name == 'Table':
|
|
39
|
+
instance = obj(columns=['Col1'], data=[['Data1']])
|
|
40
|
+
elif _name == 'Tabs':
|
|
41
|
+
instance = obj(tabs=['Tab1'], panels=[Text('Panel1')])
|
|
42
|
+
elif _name == 'Card':
|
|
43
|
+
instance = obj(title='Test Card')
|
|
44
|
+
elif _name == 'Modal':
|
|
45
|
+
instance = obj(title='Test Modal')
|
|
46
|
+
elif _name == 'Navbar':
|
|
47
|
+
instance = obj(brand='Test Navbar')
|
|
48
|
+
else:
|
|
49
|
+
# Intenta con argumentos mínimos para otros componentes
|
|
50
|
+
try:
|
|
51
|
+
instance = obj()
|
|
52
|
+
except TypeError:
|
|
53
|
+
instance = obj(id='test')
|
|
54
|
+
|
|
55
|
+
# Verifica que la instancia se creó correctamente
|
|
56
|
+
assert instance is not None, f"Failed to create instance of {_name}"
|
|
57
|
+
|
|
58
|
+
except Exception as e:
|
|
59
|
+
failures.append((f"{modname}.{_name}", 'init', repr(e)))
|
|
60
|
+
|
|
61
|
+
assert not failures, failures
|
|
62
|
+
|
|
63
|
+
if __name__ == '__main__':
|
|
64
|
+
try:
|
|
65
|
+
test_advanced_components()
|
|
66
|
+
print('test_advanced_components: OK')
|
|
67
|
+
except AssertionError as e:
|
|
68
|
+
print('test_advanced_components: FAIL', e)
|
|
69
|
+
sys.exit(1)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import importlib, inspect, sys, os
|
|
2
|
+
from dars.core.component import Component
|
|
3
|
+
|
|
4
|
+
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'dars'))
|
|
5
|
+
if project_root not in sys.path:
|
|
6
|
+
sys.path.insert(0, project_root)
|
|
7
|
+
|
|
8
|
+
failures = []
|
|
9
|
+
|
|
10
|
+
def test_basic_components():
|
|
11
|
+
base_pkg = 'dars.components.basic'
|
|
12
|
+
try:
|
|
13
|
+
pkg = importlib.import_module(base_pkg)
|
|
14
|
+
except Exception as e:
|
|
15
|
+
failures.append((base_pkg, 'import', repr(e)))
|
|
16
|
+
return
|
|
17
|
+
|
|
18
|
+
pkg_path = os.path.dirname(pkg.__file__)
|
|
19
|
+
for fname in os.listdir(pkg_path):
|
|
20
|
+
if not fname.endswith('.py') or fname.startswith('__'):
|
|
21
|
+
continue
|
|
22
|
+
|
|
23
|
+
modname = f"{base_pkg}.{fname[:-3]}"
|
|
24
|
+
try:
|
|
25
|
+
m = importlib.import_module(modname)
|
|
26
|
+
except Exception as e:
|
|
27
|
+
failures.append((modname, 'import', repr(e)))
|
|
28
|
+
continue
|
|
29
|
+
|
|
30
|
+
for _name, obj in inspect.getmembers(m, inspect.isclass):
|
|
31
|
+
try:
|
|
32
|
+
if obj is Component:
|
|
33
|
+
continue
|
|
34
|
+
if issubclass(obj, Component):
|
|
35
|
+
# Proporciona argumentos específicos para cada componente
|
|
36
|
+
if _name == 'Image':
|
|
37
|
+
instance = obj(src='test.png')
|
|
38
|
+
elif _name == 'Link':
|
|
39
|
+
instance = obj(text='Test', href='#')
|
|
40
|
+
elif _name == 'Markdown':
|
|
41
|
+
instance = obj(content='# Test')
|
|
42
|
+
elif _name == 'ProgressBar':
|
|
43
|
+
instance = obj(value=50)
|
|
44
|
+
elif _name == 'Tooltip':
|
|
45
|
+
from dars.components.basic.text import Text
|
|
46
|
+
instance = obj(text='Tip', child=Text('Hover me'))
|
|
47
|
+
elif _name == 'Button':
|
|
48
|
+
instance = obj(text='Test Button')
|
|
49
|
+
elif _name == 'Input':
|
|
50
|
+
instance = obj()
|
|
51
|
+
elif _name == 'Textarea':
|
|
52
|
+
instance = obj()
|
|
53
|
+
elif _name == 'Checkbox':
|
|
54
|
+
instance = obj(label='Test Checkbox')
|
|
55
|
+
elif _name == 'RadioButton':
|
|
56
|
+
instance = obj(label='Test Radio', name='test_radio')
|
|
57
|
+
elif _name == 'Select':
|
|
58
|
+
instance = obj(options=[{'value': 'test', 'label': 'Test'}])
|
|
59
|
+
elif _name == 'Slider':
|
|
60
|
+
instance = obj()
|
|
61
|
+
elif _name == 'DatePicker':
|
|
62
|
+
instance = obj()
|
|
63
|
+
elif _name == 'Container':
|
|
64
|
+
instance = obj()
|
|
65
|
+
elif _name == 'Text':
|
|
66
|
+
instance = obj(text='Test Text')
|
|
67
|
+
else:
|
|
68
|
+
# Intenta con argumentos mínimos para otros componentes
|
|
69
|
+
try:
|
|
70
|
+
instance = obj()
|
|
71
|
+
except TypeError:
|
|
72
|
+
instance = obj(id='test', class_name='c', style={})
|
|
73
|
+
|
|
74
|
+
# Verifica que la instancia se creó correctamente
|
|
75
|
+
assert instance is not None, f"Failed to create instance of {_name}"
|
|
76
|
+
|
|
77
|
+
except Exception as e:
|
|
78
|
+
failures.append((f"{modname}.{_name}", 'init', repr(e)))
|
|
79
|
+
|
|
80
|
+
assert not failures, failures
|
|
81
|
+
|
|
82
|
+
if __name__ == '__main__':
|
|
83
|
+
try:
|
|
84
|
+
test_basic_components()
|
|
85
|
+
print('test_basic_components: OK')
|
|
86
|
+
except AssertionError as e:
|
|
87
|
+
print('test_basic_components: FAIL', e)
|
|
88
|
+
sys.exit(1)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import importlib, sys, os
|
|
2
|
+
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'dars'))
|
|
3
|
+
if project_root not in sys.path:
|
|
4
|
+
sys.path.insert(0, project_root)
|
|
5
|
+
|
|
6
|
+
def test_core_imports():
|
|
7
|
+
import dars.core.app as app
|
|
8
|
+
import dars.core.component as component
|
|
9
|
+
import dars.cli.main as cli_main
|
|
10
|
+
# smoke tests: ensure some expected names exist
|
|
11
|
+
assert hasattr(app, 'App') or hasattr(app, 'Page'), 'app module missing App/Page'
|
|
12
|
+
assert hasattr(component, 'Component'), 'component missing Component'
|
|
13
|
+
assert hasattr(cli_main, 'main') or hasattr(cli_main, 'run'), 'cli main missing entrypoint'
|
|
14
|
+
print('core_and_cli: OK')
|
|
15
|
+
|
|
16
|
+
if __name__ == '__main__':
|
|
17
|
+
test_core_imports()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import importlib, inspect, sys, os
|
|
2
|
+
from dars.core.component import Component
|
|
3
|
+
|
|
4
|
+
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'dars'))
|
|
5
|
+
if project_root not in sys.path:
|
|
6
|
+
sys.path.insert(0, project_root)
|
|
7
|
+
|
|
8
|
+
failures = []
|
|
9
|
+
|
|
10
|
+
def test_layout_components():
|
|
11
|
+
base_pkg = 'dars.components.layout'
|
|
12
|
+
try:
|
|
13
|
+
pkg = importlib.import_module(base_pkg)
|
|
14
|
+
except Exception as e:
|
|
15
|
+
raise AssertionError(f'Could not import {base_pkg}: {e}')
|
|
16
|
+
|
|
17
|
+
pkg_path = os.path.dirname(pkg.__file__)
|
|
18
|
+
for fname in os.listdir(pkg_path):
|
|
19
|
+
if not fname.endswith('.py') or fname.startswith('__'):
|
|
20
|
+
continue
|
|
21
|
+
|
|
22
|
+
modname = f"{base_pkg}.{fname[:-3]}"
|
|
23
|
+
try:
|
|
24
|
+
m = importlib.import_module(modname)
|
|
25
|
+
except Exception as e:
|
|
26
|
+
failures.append((modname, 'import', repr(e)))
|
|
27
|
+
continue
|
|
28
|
+
|
|
29
|
+
for _name, obj in inspect.getmembers(m, inspect.isclass):
|
|
30
|
+
try:
|
|
31
|
+
if obj is Component:
|
|
32
|
+
continue
|
|
33
|
+
if issubclass(obj, Component):
|
|
34
|
+
# Intenta crear una instancia con argumentos mínimos
|
|
35
|
+
try:
|
|
36
|
+
instance = obj()
|
|
37
|
+
except TypeError:
|
|
38
|
+
try:
|
|
39
|
+
instance = obj(id='test')
|
|
40
|
+
except Exception as e:
|
|
41
|
+
failures.append((f"{modname}.{_name}", 'init', repr(e)))
|
|
42
|
+
|
|
43
|
+
# Verifica que la instancia se creó correctamente
|
|
44
|
+
if 'instance' in locals():
|
|
45
|
+
assert instance is not None, f"Failed to create instance of {_name}"
|
|
46
|
+
|
|
47
|
+
except Exception as e:
|
|
48
|
+
failures.append((f"{modname}.{_name}", 'inspect', repr(e)))
|
|
49
|
+
|
|
50
|
+
assert not failures, failures
|
|
51
|
+
|
|
52
|
+
if __name__ == '__main__':
|
|
53
|
+
try:
|
|
54
|
+
test_layout_components()
|
|
55
|
+
print('test_layout_components: OK')
|
|
56
|
+
except AssertionError as e:
|
|
57
|
+
print('test_layout_components: FAIL', e)
|
|
58
|
+
sys.exit(1)
|