quantum-framework 0.18.0__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.
- quantum/__init__.py +1 -0
- quantum/cli/__init__.py +2 -0
- quantum/cli/admin.py +131 -0
- quantum/cli/check.py +223 -0
- quantum/cli/commands/__init__.py +15 -0
- quantum/cli/commands/build.py +414 -0
- quantum/cli/commands/dev.py +185 -0
- quantum/cli/commands/docs.py +329 -0
- quantum/cli/commands/lint.py +523 -0
- quantum/cli/commands/migrate.py +548 -0
- quantum/cli/commands/new.py +622 -0
- quantum/cli/commands/serve.py +190 -0
- quantum/cli/commands/test.py +193 -0
- quantum/cli/deploy.py +810 -0
- quantum/cli/hot_reload.py +951 -0
- quantum/cli/jobs.py +356 -0
- quantum/cli/mq.py +582 -0
- quantum/cli/pkg.py +390 -0
- quantum/cli/runner.py +565 -0
- quantum/cli/server_process.py +159 -0
- quantum/cli/utils.py +334 -0
- quantum/compiler/__init__.py +30 -0
- quantum/compiler/base_generator.py +367 -0
- quantum/compiler/cli.py +295 -0
- quantum/compiler/expression_transformer.py +444 -0
- quantum/compiler/javascript/__init__.py +10 -0
- quantum/compiler/javascript/generator.py +659 -0
- quantum/compiler/optimizer.py +270 -0
- quantum/compiler/python/__init__.py +10 -0
- quantum/compiler/python/generator.py +883 -0
- quantum/compiler/python/runtime.py +863 -0
- quantum/compiler/transpiler.py +330 -0
- quantum/core/__init__.py +3 -0
- quantum/core/ast_nodes.py +2619 -0
- quantum/core/config_env.py +54 -0
- quantum/core/docs_links.py +8 -0
- quantum/core/expression_diagnostics.py +87 -0
- quantum/core/expression_stdlib.py +208 -0
- quantum/core/expressions.py +677 -0
- quantum/core/features/agents/src/__init__.py +30 -0
- quantum/core/features/agents/src/ast_node.py +540 -0
- quantum/core/features/conditionals/src/__init__.py +8 -0
- quantum/core/features/conditionals/src/ast_node.py +68 -0
- quantum/core/features/data_import/src/__init__.py +0 -0
- quantum/core/features/data_import/src/ast_node.py +292 -0
- quantum/core/features/data_import/src/runtime.py +533 -0
- quantum/core/features/dump/src/__init__.py +12 -0
- quantum/core/features/dump/src/ast_node.py +106 -0
- quantum/core/features/dump/src/parser.py +61 -0
- quantum/core/features/dump/src/runtime.py +246 -0
- quantum/core/features/functions/src/__init__.py +8 -0
- quantum/core/features/functions/src/ast_node.py +149 -0
- quantum/core/features/game_engine_2d/src/__init__.py +19 -0
- quantum/core/features/game_engine_2d/src/ast_nodes.py +1719 -0
- quantum/core/features/game_engine_2d/src/parser.py +983 -0
- quantum/core/features/invocation/src/__init__.py +0 -0
- quantum/core/features/invocation/src/ast_node.py +147 -0
- quantum/core/features/invocation/src/runtime.py +332 -0
- quantum/core/features/knowledge_base/src/__init__.py +6 -0
- quantum/core/features/knowledge_base/src/ast_node.py +113 -0
- quantum/core/features/knowledge_base/src/parser.py +82 -0
- quantum/core/features/logging/src/__init__.py +12 -0
- quantum/core/features/logging/src/ast_node.py +111 -0
- quantum/core/features/logging/src/parser.py +50 -0
- quantum/core/features/logging/src/runtime.py +190 -0
- quantum/core/features/loops/src/__init__.py +8 -0
- quantum/core/features/loops/src/ast_node.py +60 -0
- quantum/core/features/query/src/__init__.py +0 -0
- quantum/core/features/query/src/query_validators.py +20 -0
- quantum/core/features/state_management/src/__init__.py +11 -0
- quantum/core/features/state_management/src/ast_node.py +121 -0
- quantum/core/features/terminal_engine/src/__init__.py +21 -0
- quantum/core/features/terminal_engine/src/ast_nodes.py +560 -0
- quantum/core/features/terminal_engine/src/parser.py +361 -0
- quantum/core/features/testing_engine/src/__init__.py +41 -0
- quantum/core/features/testing_engine/src/ast_nodes.py +1212 -0
- quantum/core/features/testing_engine/src/parser.py +604 -0
- quantum/core/features/theming/src/__init__.py +48 -0
- quantum/core/features/theming/src/ast_node.py +137 -0
- quantum/core/features/theming/src/presets.py +405 -0
- quantum/core/features/ui_engine/src/__init__.py +20 -0
- quantum/core/features/ui_engine/src/ast_nodes.py +1913 -0
- quantum/core/features/ui_engine/src/parser.py +1192 -0
- quantum/core/features/websocket/src/__init__.py +24 -0
- quantum/core/features/websocket/src/ast_node.py +247 -0
- quantum/core/guards.py +53 -0
- quantum/core/html_compat.py +299 -0
- quantum/core/parser.py +1551 -0
- quantum/core/parser_registry.py +213 -0
- quantum/core/parsers/__init__.py +76 -0
- quantum/core/parsers/ai/__init__.py +12 -0
- quantum/core/parsers/ai/agent_parser.py +106 -0
- quantum/core/parsers/ai/knowledge_parser.py +86 -0
- quantum/core/parsers/ai/llm_parser.py +78 -0
- quantum/core/parsers/ai/team_parser.py +88 -0
- quantum/core/parsers/base.py +322 -0
- quantum/core/parsers/composition/__init__.py +10 -0
- quantum/core/parsers/composition/import_parser.py +50 -0
- quantum/core/parsers/composition/slot_parser.py +48 -0
- quantum/core/parsers/control_flow/__init__.py +11 -0
- quantum/core/parsers/control_flow/if_parser.py +71 -0
- quantum/core/parsers/control_flow/loop_parser.py +105 -0
- quantum/core/parsers/control_flow/set_parser.py +93 -0
- quantum/core/parsers/data/__init__.py +12 -0
- quantum/core/parsers/data/data_parser.py +229 -0
- quantum/core/parsers/data/invoke_parser.py +133 -0
- quantum/core/parsers/data/query_parser.py +213 -0
- quantum/core/parsers/data/transaction_parser.py +86 -0
- quantum/core/parsers/events/__init__.py +9 -0
- quantum/core/parsers/events/dispatch_event_parser.py +44 -0
- quantum/core/parsers/forms/__init__.py +11 -0
- quantum/core/parsers/forms/action_parser.py +79 -0
- quantum/core/parsers/forms/flash_parser.py +34 -0
- quantum/core/parsers/forms/redirect_parser.py +33 -0
- quantum/core/parsers/functions/__init__.py +11 -0
- quantum/core/parsers/functions/function_parser.py +98 -0
- quantum/core/parsers/functions/param_parser.py +73 -0
- quantum/core/parsers/functions/return_parser.py +31 -0
- quantum/core/parsers/html/__init__.py +10 -0
- quantum/core/parsers/html/component_call_parser.py +130 -0
- quantum/core/parsers/html/html_parser.py +115 -0
- quantum/core/parsers/jobs/__init__.py +11 -0
- quantum/core/parsers/jobs/job_parser.py +71 -0
- quantum/core/parsers/jobs/schedule_parser.py +62 -0
- quantum/core/parsers/jobs/thread_parser.py +57 -0
- quantum/core/parsers/messaging/__init__.py +17 -0
- quantum/core/parsers/messaging/message_ack_parser.py +30 -0
- quantum/core/parsers/messaging/message_nack_parser.py +30 -0
- quantum/core/parsers/messaging/message_parser.py +114 -0
- quantum/core/parsers/messaging/queue_parser.py +61 -0
- quantum/core/parsers/messaging/websocket_parser.py +121 -0
- quantum/core/parsers/routing/__init__.py +9 -0
- quantum/core/parsers/routing/route_parser.py +41 -0
- quantum/core/parsers/scripting/__init__.py +12 -0
- quantum/core/parsers/scripting/pyclass_parser.py +62 -0
- quantum/core/parsers/scripting/pydecorator_parser.py +68 -0
- quantum/core/parsers/scripting/pyimport_parser.py +52 -0
- quantum/core/parsers/scripting/python_parser.py +49 -0
- quantum/core/parsers/services/__init__.py +12 -0
- quantum/core/parsers/services/dump_parser.py +52 -0
- quantum/core/parsers/services/file_parser.py +48 -0
- quantum/core/parsers/services/log_parser.py +46 -0
- quantum/core/parsers/services/mail_parser.py +65 -0
- quantum/core/tiers.py +164 -0
- quantum/core/xml_lines.py +81 -0
- quantum/packages/__init__.py +28 -0
- quantum/packages/manager.py +413 -0
- quantum/packages/manifest.py +351 -0
- quantum/packages/registry.py +399 -0
- quantum/packages/resolver.py +336 -0
- quantum/plugins/__init__.py +33 -0
- quantum/plugins/hooks.py +329 -0
- quantum/plugins/loader.py +479 -0
- quantum/plugins/manifest.py +336 -0
- quantum/plugins/registry.py +371 -0
- quantum/runtime/__init__.py +25 -0
- quantum/runtime/action_handler.py +532 -0
- quantum/runtime/adapters/__init__.py +88 -0
- quantum/runtime/adapters/memory_adapter.py +690 -0
- quantum/runtime/adapters/rabbitmq_adapter.py +715 -0
- quantum/runtime/adapters/redis_adapter.py +582 -0
- quantum/runtime/adapters/sqlite_adapter.py +414 -0
- quantum/runtime/agent_service.py +1133 -0
- quantum/runtime/ast_cache.py +506 -0
- quantum/runtime/auth_service.py +267 -0
- quantum/runtime/component.py +1048 -0
- quantum/runtime/component_composer.py +133 -0
- quantum/runtime/component_resolver.py +174 -0
- quantum/runtime/conditions.py +54 -0
- quantum/runtime/database_service.py +595 -0
- quantum/runtime/db_schema.py +100 -0
- quantum/runtime/dev_panel.py +178 -0
- quantum/runtime/email_service.py +162 -0
- quantum/runtime/error_handler.py +295 -0
- quantum/runtime/execution_context.py +283 -0
- quantum/runtime/executor_registry.py +178 -0
- quantum/runtime/executors/__init__.py +71 -0
- quantum/runtime/executors/ai/__init__.py +12 -0
- quantum/runtime/executors/ai/agent_executor.py +217 -0
- quantum/runtime/executors/ai/knowledge_executor.py +114 -0
- quantum/runtime/executors/ai/llm_executor.py +153 -0
- quantum/runtime/executors/ai/team_executor.py +171 -0
- quantum/runtime/executors/base.py +264 -0
- quantum/runtime/executors/control_flow/__init__.py +12 -0
- quantum/runtime/executors/control_flow/if_executor.py +98 -0
- quantum/runtime/executors/control_flow/loop_executor.py +308 -0
- quantum/runtime/executors/control_flow/redirect_executor.py +43 -0
- quantum/runtime/executors/control_flow/set_executor.py +464 -0
- quantum/runtime/executors/data/__init__.py +12 -0
- quantum/runtime/executors/data/data_executor.py +156 -0
- quantum/runtime/executors/data/invoke_executor.py +228 -0
- quantum/runtime/executors/data/query_executor.py +290 -0
- quantum/runtime/executors/data/transaction_executor.py +91 -0
- quantum/runtime/executors/jobs/__init__.py +11 -0
- quantum/runtime/executors/jobs/job_executor.py +190 -0
- quantum/runtime/executors/jobs/schedule_executor.py +132 -0
- quantum/runtime/executors/jobs/thread_executor.py +127 -0
- quantum/runtime/executors/messaging/__init__.py +17 -0
- quantum/runtime/executors/messaging/message_ack_executor.py +51 -0
- quantum/runtime/executors/messaging/message_executor.py +174 -0
- quantum/runtime/executors/messaging/queue_executor.py +103 -0
- quantum/runtime/executors/messaging/websocket_executor.py +197 -0
- quantum/runtime/executors/scripting/__init__.py +11 -0
- quantum/runtime/executors/scripting/pyclass_executor.py +90 -0
- quantum/runtime/executors/scripting/pyimport_executor.py +81 -0
- quantum/runtime/executors/scripting/python_executor.py +249 -0
- quantum/runtime/executors/services/__init__.py +12 -0
- quantum/runtime/executors/services/dump_executor.py +72 -0
- quantum/runtime/executors/services/file_executor.py +89 -0
- quantum/runtime/executors/services/log_executor.py +77 -0
- quantum/runtime/executors/services/mail_executor.py +81 -0
- quantum/runtime/expression_cache.py +498 -0
- quantum/runtime/file_upload_service.py +326 -0
- quantum/runtime/function_registry.py +118 -0
- quantum/runtime/game_builder.py +166 -0
- quantum/runtime/game_code_generator.py +2371 -0
- quantum/runtime/game_templates.py +2006 -0
- quantum/runtime/godot_code_generator.py +4681 -0
- quantum/runtime/godot_templates.py +1449 -0
- quantum/runtime/job_executor.py +1599 -0
- quantum/runtime/knowledge_service.py +546 -0
- quantum/runtime/llm_cache.py +100 -0
- quantum/runtime/llm_providers.py +704 -0
- quantum/runtime/llm_service.py +287 -0
- quantum/runtime/local_server.py +28 -0
- quantum/runtime/logging_setup.py +141 -0
- quantum/runtime/message_broker.py +364 -0
- quantum/runtime/message_queue_service.py +571 -0
- quantum/runtime/param_validation.py +218 -0
- quantum/runtime/pypy_compat.py +317 -0
- quantum/runtime/python_bridge.py +698 -0
- quantum/runtime/query_validators.py +304 -0
- quantum/runtime/renderer.py +734 -0
- quantum/runtime/service_container.py +470 -0
- quantum/runtime/table_params.py +163 -0
- quantum/runtime/terminal_builder.py +76 -0
- quantum/runtime/terminal_code_generator.py +607 -0
- quantum/runtime/terminal_templates.py +243 -0
- quantum/runtime/testing_builder.py +77 -0
- quantum/runtime/testing_code_generator.py +833 -0
- quantum/runtime/testing_templates.py +85 -0
- quantum/runtime/ui_builder.py +222 -0
- quantum/runtime/ui_console.py +405 -0
- quantum/runtime/ui_desktop.py +56 -0
- quantum/runtime/ui_form_rules.py +193 -0
- quantum/runtime/ui_html_adapter.py +2567 -0
- quantum/runtime/ui_html_templates.py +2106 -0
- quantum/runtime/ui_mobile_adapter.py +1832 -0
- quantum/runtime/ui_mobile_templates.py +1003 -0
- quantum/runtime/ui_page_renderer.py +392 -0
- quantum/runtime/ui_pager.py +73 -0
- quantum/runtime/ui_table_edit.py +139 -0
- quantum/runtime/ui_textual_adapter.py +1866 -0
- quantum/runtime/ui_textual_templates.py +45 -0
- quantum/runtime/ui_tokens.py +465 -0
- quantum/runtime/ui_validator.py +365 -0
- quantum/runtime/ui_view.py +221 -0
- quantum/runtime/validators.py +256 -0
- quantum/runtime/web_server.py +2131 -0
- quantum/runtime/websocket_adapter.py +501 -0
- quantum/runtime/websocket_service.py +585 -0
- quantum/runtime/websocket_transport.py +289 -0
- quantum/runtime/wsgi.py +101 -0
- quantum/services.py +109 -0
- quantum/utils/__init__.py +1 -0
- quantum_admin/__init__.py +4 -0
- quantum_admin/assets/quantum-admin-connectors.js +123 -0
- quantum_admin/assets/quantum-admin.css +2058 -0
- quantum_admin/assets/quantum-source-highlight.js +106 -0
- quantum_admin/backend/__init__.py +4 -0
- quantum_admin/backend/audit_service.py +346 -0
- quantum_admin/backend/auth_service.py +394 -0
- quantum_admin/backend/component_discovery.py +766 -0
- quantum_admin/backend/config_generator.py +586 -0
- quantum_admin/backend/connector_service.py +1016 -0
- quantum_admin/backend/crud.py +557 -0
- quantum_admin/backend/database.py +226 -0
- quantum_admin/backend/db_setup_service.py +193 -0
- quantum_admin/backend/deploy_service.py +698 -0
- quantum_admin/backend/docker_service.py +422 -0
- quantum_admin/backend/environment_service.py +418 -0
- quantum_admin/backend/git_service.py +370 -0
- quantum_admin/backend/health_service.py +390 -0
- quantum_admin/backend/job_service.py +347 -0
- quantum_admin/backend/log_service.py +331 -0
- quantum_admin/backend/main.py +14426 -0
- quantum_admin/backend/models.py +986 -0
- quantum_admin/backend/pipeline_service.py +812 -0
- quantum_admin/backend/resource_manager.py +1118 -0
- quantum_admin/backend/schemas.py +419 -0
- quantum_admin/backend/secret_manager.py +277 -0
- quantum_admin/backend/settings_service.py +488 -0
- quantum_admin/backend/template_service.py +710 -0
- quantum_admin/backend/test_execution_service.py +364 -0
- quantum_admin/backend/test_generator.py +782 -0
- quantum_admin/backend/webhook_service.py +454 -0
- quantum_admin/backend/websocket_manager.py +360 -0
- quantum_admin/components/admin/_layout/AdminShell.q +121 -0
- quantum_admin/components/admin/agents.q +107 -0
- quantum_admin/components/admin/app/[name].q +558 -0
- quantum_admin/components/admin/applications.q +160 -0
- quantum_admin/components/admin/component/[...path].q +205 -0
- quantum_admin/components/admin/components.q +59 -0
- quantum_admin/components/admin/connectors.q +283 -0
- quantum_admin/components/admin/dashboard.q +86 -0
- quantum_admin/components/admin/database.q +95 -0
- quantum_admin/components/admin/features.q +69 -0
- quantum_admin/components/admin/index.q +12 -0
- quantum_admin/components/admin/jobs.q +75 -0
- quantum_admin/components/admin/login.q +65 -0
- quantum_admin/components/admin/logout.q +11 -0
- quantum_admin/components/admin/settings.q +174 -0
- quantum_admin/components/admin/source.q +45 -0
- quantum_admin/components/admin/tests.q +73 -0
- quantum_admin/run.py +13 -0
- quantum_admin/services/__init__.py +16 -0
- quantum_admin/services/_base.py +84 -0
- quantum_admin/services/_component_test_generator.py +205 -0
- quantum_admin/services/_yaml_editor.py +82 -0
- quantum_admin/services/apps.py +330 -0
- quantum_admin/services/auth.py +61 -0
- quantum_admin/services/components.py +210 -0
- quantum_admin/services/connectors.py +164 -0
- quantum_admin/services/projects.py +189 -0
- quantum_admin/services/repository.py +223 -0
- quantum_admin/services/settings.py +150 -0
- quantum_admin/services/yaml_import.py +118 -0
- quantum_framework-0.18.0.dist-info/METADATA +281 -0
- quantum_framework-0.18.0.dist-info/RECORD +333 -0
- quantum_framework-0.18.0.dist-info/WHEEL +5 -0
- quantum_framework-0.18.0.dist-info/entry_points.txt +2 -0
- quantum_framework-0.18.0.dist-info/licenses/LICENSE +21 -0
- quantum_framework-0.18.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Quantum CLI - Serve Command
|
|
3
|
+
|
|
4
|
+
Serve built files with a static file server.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Optional
|
|
11
|
+
import mimetypes
|
|
12
|
+
|
|
13
|
+
import click
|
|
14
|
+
|
|
15
|
+
from quantum.cli.utils import get_console, find_project_root
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@click.command('serve')
|
|
19
|
+
@click.option('--port', '-p', type=int, default=8080, help='Port to serve on')
|
|
20
|
+
@click.option('--host', '-h', type=str, default='0.0.0.0', help='Host to bind to')
|
|
21
|
+
@click.option('--directory', '-d', type=click.Path(exists=True), default='./dist',
|
|
22
|
+
help='Directory to serve')
|
|
23
|
+
@click.option('--cors', is_flag=True, help='Enable CORS headers')
|
|
24
|
+
@click.option('--spa', is_flag=True, help='SPA mode - serve index.html for all routes')
|
|
25
|
+
@click.option('--quiet', '-q', is_flag=True, help='Quiet mode')
|
|
26
|
+
def serve(port: int, host: str, directory: str, cors: bool, spa: bool, quiet: bool):
|
|
27
|
+
"""Serve built files with a static file server.
|
|
28
|
+
|
|
29
|
+
Serves the contents of the dist directory (or specified directory).
|
|
30
|
+
|
|
31
|
+
Examples:
|
|
32
|
+
|
|
33
|
+
quantum serve
|
|
34
|
+
|
|
35
|
+
quantum serve --port 3000
|
|
36
|
+
|
|
37
|
+
quantum serve --directory ./build --cors
|
|
38
|
+
|
|
39
|
+
quantum serve --spa # For single-page applications
|
|
40
|
+
"""
|
|
41
|
+
console = get_console(quiet=quiet)
|
|
42
|
+
|
|
43
|
+
# Resolve directory path
|
|
44
|
+
serve_dir = Path(directory)
|
|
45
|
+
if not serve_dir.is_absolute():
|
|
46
|
+
project_root = find_project_root() or Path.cwd()
|
|
47
|
+
serve_dir = project_root / directory
|
|
48
|
+
|
|
49
|
+
if not serve_dir.exists():
|
|
50
|
+
console.error(f"Directory not found: {serve_dir}")
|
|
51
|
+
console.info("Run 'quantum build' first to create build output")
|
|
52
|
+
raise click.Abort()
|
|
53
|
+
|
|
54
|
+
# Check for index.html
|
|
55
|
+
index_file = serve_dir / 'index.html'
|
|
56
|
+
if not index_file.exists():
|
|
57
|
+
# Look for any .html file
|
|
58
|
+
html_files = list(serve_dir.glob('*.html'))
|
|
59
|
+
if html_files:
|
|
60
|
+
console.warning(f"No index.html found, but found: {', '.join(f.name for f in html_files[:3])}")
|
|
61
|
+
else:
|
|
62
|
+
console.warning("No HTML files found in directory")
|
|
63
|
+
|
|
64
|
+
url = f"http://{host if host != '0.0.0.0' else 'localhost'}:{port}"
|
|
65
|
+
|
|
66
|
+
console.header(
|
|
67
|
+
"Quantum Static Server",
|
|
68
|
+
f"Serving: {serve_dir}"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
console.panel(
|
|
72
|
+
f"[bold]URL:[/bold] {url}\n"
|
|
73
|
+
f"[bold]Directory:[/bold] {serve_dir}\n"
|
|
74
|
+
f"[bold]CORS:[/bold] {'Enabled' if cors else 'Disabled'}\n"
|
|
75
|
+
f"[bold]SPA Mode:[/bold] {'Enabled' if spa else 'Disabled'}",
|
|
76
|
+
title="Server Configuration",
|
|
77
|
+
style="green"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
console.print()
|
|
81
|
+
console.info(f"Server running at {url}")
|
|
82
|
+
console.print("[dim]Press Ctrl+C to stop[/dim]")
|
|
83
|
+
console.print()
|
|
84
|
+
|
|
85
|
+
# Start server
|
|
86
|
+
try:
|
|
87
|
+
_run_server(serve_dir, host, port, cors, spa, console)
|
|
88
|
+
except KeyboardInterrupt:
|
|
89
|
+
console.print()
|
|
90
|
+
console.info("Server stopped")
|
|
91
|
+
except Exception as e:
|
|
92
|
+
console.error(f"Server error: {e}")
|
|
93
|
+
raise click.Abort()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _run_server(
|
|
97
|
+
directory: Path,
|
|
98
|
+
host: str,
|
|
99
|
+
port: int,
|
|
100
|
+
cors: bool,
|
|
101
|
+
spa: bool,
|
|
102
|
+
console
|
|
103
|
+
):
|
|
104
|
+
"""Run the static file server."""
|
|
105
|
+
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
|
106
|
+
import urllib.parse
|
|
107
|
+
|
|
108
|
+
class QuantumHandler(SimpleHTTPRequestHandler):
|
|
109
|
+
"""Custom handler with CORS and SPA support."""
|
|
110
|
+
|
|
111
|
+
def __init__(self, *args, **kwargs):
|
|
112
|
+
super().__init__(*args, directory=str(directory), **kwargs)
|
|
113
|
+
|
|
114
|
+
def log_message(self, format, *args):
|
|
115
|
+
"""Log requests to console."""
|
|
116
|
+
message = format % args
|
|
117
|
+
# Parse status code
|
|
118
|
+
parts = message.split('"')
|
|
119
|
+
if len(parts) >= 3:
|
|
120
|
+
status = parts[2].strip().split()[0]
|
|
121
|
+
method_path = parts[1]
|
|
122
|
+
if status.startswith('2'):
|
|
123
|
+
console.print(f"[green]{status}[/green] {method_path}")
|
|
124
|
+
elif status.startswith('3'):
|
|
125
|
+
console.print(f"[yellow]{status}[/yellow] {method_path}")
|
|
126
|
+
elif status.startswith('4') or status.startswith('5'):
|
|
127
|
+
console.print(f"[red]{status}[/red] {method_path}")
|
|
128
|
+
else:
|
|
129
|
+
console.print(f"{status} {method_path}")
|
|
130
|
+
else:
|
|
131
|
+
console.print(message)
|
|
132
|
+
|
|
133
|
+
def end_headers(self):
|
|
134
|
+
"""Add CORS headers if enabled."""
|
|
135
|
+
if cors:
|
|
136
|
+
self.send_header('Access-Control-Allow-Origin', '*')
|
|
137
|
+
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
|
|
138
|
+
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
|
|
139
|
+
super().end_headers()
|
|
140
|
+
|
|
141
|
+
def do_OPTIONS(self):
|
|
142
|
+
"""Handle CORS preflight requests."""
|
|
143
|
+
if cors:
|
|
144
|
+
self.send_response(200)
|
|
145
|
+
self.end_headers()
|
|
146
|
+
else:
|
|
147
|
+
self.send_error(405, "Method Not Allowed")
|
|
148
|
+
|
|
149
|
+
def do_GET(self):
|
|
150
|
+
"""Handle GET requests with SPA support."""
|
|
151
|
+
if spa:
|
|
152
|
+
# Parse the URL path
|
|
153
|
+
parsed = urllib.parse.urlparse(self.path)
|
|
154
|
+
path = parsed.path
|
|
155
|
+
|
|
156
|
+
# Check if file exists
|
|
157
|
+
file_path = directory / path.lstrip('/')
|
|
158
|
+
|
|
159
|
+
if not file_path.exists() and not path.startswith('/assets'):
|
|
160
|
+
# Check if it's a file request (has extension)
|
|
161
|
+
if '.' not in Path(path).name:
|
|
162
|
+
# Serve index.html for SPA routes
|
|
163
|
+
self.path = '/index.html'
|
|
164
|
+
|
|
165
|
+
super().do_GET()
|
|
166
|
+
|
|
167
|
+
def guess_type(self, path):
|
|
168
|
+
"""Guess content type with better defaults."""
|
|
169
|
+
content_type, _ = mimetypes.guess_type(path)
|
|
170
|
+
if content_type:
|
|
171
|
+
return content_type
|
|
172
|
+
|
|
173
|
+
# Additional mappings
|
|
174
|
+
ext = Path(path).suffix.lower()
|
|
175
|
+
type_map = {
|
|
176
|
+
'.q': 'text/xml',
|
|
177
|
+
'.yaml': 'text/yaml',
|
|
178
|
+
'.yml': 'text/yaml',
|
|
179
|
+
'.wasm': 'application/wasm',
|
|
180
|
+
'.mjs': 'application/javascript',
|
|
181
|
+
}
|
|
182
|
+
return type_map.get(ext, 'application/octet-stream')
|
|
183
|
+
|
|
184
|
+
# Create and start server
|
|
185
|
+
server = HTTPServer((host, port), QuantumHandler)
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
server.serve_forever()
|
|
189
|
+
finally:
|
|
190
|
+
server.server_close()
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Quantum CLI - Test Command
|
|
3
|
+
|
|
4
|
+
Run tests for Quantum applications.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
import subprocess
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Optional, List
|
|
12
|
+
|
|
13
|
+
import click
|
|
14
|
+
|
|
15
|
+
from quantum.cli.utils import get_console, find_project_root
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@click.command('test')
|
|
19
|
+
@click.argument('path', required=False, type=click.Path())
|
|
20
|
+
@click.option('--pattern', '-p', type=str, default='test_*.py',
|
|
21
|
+
help='Test file pattern')
|
|
22
|
+
@click.option('--coverage', '-c', is_flag=True, help='Run with coverage')
|
|
23
|
+
@click.option('--verbose', '-v', is_flag=True, help='Verbose output')
|
|
24
|
+
@click.option('--watch', '-w', is_flag=True, help='Watch mode - rerun on changes')
|
|
25
|
+
@click.option('--filter', '-k', type=str, help='Filter tests by name pattern')
|
|
26
|
+
@click.option('--markers', '-m', type=str, help='Run tests with specific markers')
|
|
27
|
+
@click.option('--fail-fast', '-x', is_flag=True, help='Stop on first failure')
|
|
28
|
+
@click.option('--quiet', '-q', is_flag=True, help='Quiet mode')
|
|
29
|
+
def test(
|
|
30
|
+
path: Optional[str],
|
|
31
|
+
pattern: str,
|
|
32
|
+
coverage: bool,
|
|
33
|
+
verbose: bool,
|
|
34
|
+
watch: bool,
|
|
35
|
+
filter: Optional[str],
|
|
36
|
+
markers: Optional[str],
|
|
37
|
+
fail_fast: bool,
|
|
38
|
+
quiet: bool
|
|
39
|
+
):
|
|
40
|
+
"""Run tests for Quantum applications.
|
|
41
|
+
|
|
42
|
+
Uses pytest to run tests from the tests/ directory.
|
|
43
|
+
|
|
44
|
+
Examples:
|
|
45
|
+
|
|
46
|
+
quantum test
|
|
47
|
+
|
|
48
|
+
quantum test tests/unit/
|
|
49
|
+
|
|
50
|
+
quantum test --coverage
|
|
51
|
+
|
|
52
|
+
quantum test -k "test_parser" -v
|
|
53
|
+
|
|
54
|
+
quantum test --watch
|
|
55
|
+
"""
|
|
56
|
+
console = get_console(quiet=quiet)
|
|
57
|
+
|
|
58
|
+
# Find project root
|
|
59
|
+
project_root = find_project_root()
|
|
60
|
+
if not project_root:
|
|
61
|
+
console.error("No Quantum project found")
|
|
62
|
+
raise click.Abort()
|
|
63
|
+
|
|
64
|
+
# Determine test path
|
|
65
|
+
if path:
|
|
66
|
+
test_path = Path(path)
|
|
67
|
+
if not test_path.is_absolute():
|
|
68
|
+
test_path = project_root / path
|
|
69
|
+
else:
|
|
70
|
+
test_path = project_root / 'tests'
|
|
71
|
+
|
|
72
|
+
if not test_path.exists():
|
|
73
|
+
console.error(f"Test path not found: {test_path}")
|
|
74
|
+
console.info("Create a 'tests/' directory with test files")
|
|
75
|
+
raise click.Abort()
|
|
76
|
+
|
|
77
|
+
console.header(
|
|
78
|
+
"Running Quantum Tests",
|
|
79
|
+
f"Path: {test_path}"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Check for pytest
|
|
83
|
+
try:
|
|
84
|
+
subprocess.run(['pytest', '--version'], capture_output=True, check=True)
|
|
85
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
86
|
+
console.error("pytest not found. Install with: pip install pytest")
|
|
87
|
+
raise click.Abort()
|
|
88
|
+
|
|
89
|
+
# Build pytest command
|
|
90
|
+
cmd = ['pytest', str(test_path)]
|
|
91
|
+
|
|
92
|
+
if verbose:
|
|
93
|
+
cmd.append('-v')
|
|
94
|
+
|
|
95
|
+
if fail_fast:
|
|
96
|
+
cmd.append('-x')
|
|
97
|
+
|
|
98
|
+
if filter:
|
|
99
|
+
cmd.extend(['-k', filter])
|
|
100
|
+
|
|
101
|
+
if markers:
|
|
102
|
+
cmd.extend(['-m', markers])
|
|
103
|
+
|
|
104
|
+
if coverage:
|
|
105
|
+
# Check for pytest-cov
|
|
106
|
+
try:
|
|
107
|
+
import pytest_cov
|
|
108
|
+
except ImportError:
|
|
109
|
+
console.warning("pytest-cov not found. Install with: pip install pytest-cov")
|
|
110
|
+
console.info("Running without coverage...")
|
|
111
|
+
else:
|
|
112
|
+
cmd.extend(['--cov=src', '--cov-report=term-missing', '--cov-report=html'])
|
|
113
|
+
|
|
114
|
+
# Add src to PYTHONPATH
|
|
115
|
+
env = os.environ.copy()
|
|
116
|
+
src_path = str(project_root / 'src')
|
|
117
|
+
env['PYTHONPATH'] = src_path + os.pathsep + env.get('PYTHONPATH', '')
|
|
118
|
+
|
|
119
|
+
console.info(f"Running: {' '.join(cmd)}")
|
|
120
|
+
console.print()
|
|
121
|
+
|
|
122
|
+
if watch:
|
|
123
|
+
_watch_and_test(project_root, cmd, env, console)
|
|
124
|
+
else:
|
|
125
|
+
# Run tests
|
|
126
|
+
result = subprocess.run(cmd, cwd=project_root, env=env)
|
|
127
|
+
|
|
128
|
+
if result.returncode == 0:
|
|
129
|
+
console.print()
|
|
130
|
+
console.success("All tests passed!")
|
|
131
|
+
else:
|
|
132
|
+
console.print()
|
|
133
|
+
console.error(f"Tests failed with exit code {result.returncode}")
|
|
134
|
+
sys.exit(result.returncode)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _watch_and_test(project_root: Path, cmd: List[str], env: dict, console):
|
|
138
|
+
"""Watch for changes and rerun tests."""
|
|
139
|
+
import time
|
|
140
|
+
import signal
|
|
141
|
+
|
|
142
|
+
last_mtimes = {}
|
|
143
|
+
|
|
144
|
+
def get_file_mtimes():
|
|
145
|
+
mtimes = {}
|
|
146
|
+
for ext in ['.py', '.q']:
|
|
147
|
+
for f in project_root.rglob(f'*{ext}'):
|
|
148
|
+
# Skip __pycache__
|
|
149
|
+
if '__pycache__' in str(f):
|
|
150
|
+
continue
|
|
151
|
+
try:
|
|
152
|
+
mtimes[f] = f.stat().st_mtime
|
|
153
|
+
except OSError:
|
|
154
|
+
pass
|
|
155
|
+
return mtimes
|
|
156
|
+
|
|
157
|
+
def run_tests():
|
|
158
|
+
console.print()
|
|
159
|
+
console.info("Running tests...")
|
|
160
|
+
console.print()
|
|
161
|
+
subprocess.run(cmd, cwd=project_root, env=env)
|
|
162
|
+
|
|
163
|
+
def signal_handler(sig, frame):
|
|
164
|
+
console.print()
|
|
165
|
+
console.info("Stopping watch mode...")
|
|
166
|
+
raise SystemExit(0)
|
|
167
|
+
|
|
168
|
+
signal.signal(signal.SIGINT, signal_handler)
|
|
169
|
+
|
|
170
|
+
# Initial run
|
|
171
|
+
run_tests()
|
|
172
|
+
last_mtimes = get_file_mtimes()
|
|
173
|
+
|
|
174
|
+
console.print()
|
|
175
|
+
console.info("Watching for changes... (Ctrl+C to stop)")
|
|
176
|
+
|
|
177
|
+
while True:
|
|
178
|
+
time.sleep(1)
|
|
179
|
+
current_mtimes = get_file_mtimes()
|
|
180
|
+
|
|
181
|
+
changed = []
|
|
182
|
+
for f, mtime in current_mtimes.items():
|
|
183
|
+
if f not in last_mtimes or mtime > last_mtimes[f]:
|
|
184
|
+
changed.append(f)
|
|
185
|
+
|
|
186
|
+
if changed:
|
|
187
|
+
console.print()
|
|
188
|
+
for f in changed:
|
|
189
|
+
rel_path = f.relative_to(project_root)
|
|
190
|
+
console.info(f"Changed: {rel_path}")
|
|
191
|
+
|
|
192
|
+
run_tests()
|
|
193
|
+
last_mtimes = current_mtimes
|