py-wlcli 0.8.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.
- py_wlcli-0.8.0.dist-info/METADATA +139 -0
- py_wlcli-0.8.0.dist-info/RECORD +320 -0
- py_wlcli-0.8.0.dist-info/WHEEL +4 -0
- py_wlcli-0.8.0.dist-info/entry_points.txt +2 -0
- py_wlcli-0.8.0.dist-info/licenses/LICENSE +21 -0
- wl_cli/__init__.py +27 -0
- wl_cli/__main__.py +130 -0
- wl_cli/capabilities.py +79 -0
- wl_cli/cc/__init__.py +5 -0
- wl_cli/cc/checks.py +1019 -0
- wl_cli/cc/cli.py +370 -0
- wl_cli/cc/mutate.py +1350 -0
- wl_cli/cli_click.py +156 -0
- wl_cli/commands/__init__.py +84 -0
- wl_cli/commands/base.py +80 -0
- wl_cli/commands/buildcommands/__init__.py +1 -0
- wl_cli/commands/buildcommands/build.py +71 -0
- wl_cli/commands/buildcommands/build_utils.py +47 -0
- wl_cli/commands/buildcommands/builders/__init__.py +18 -0
- wl_cli/commands/buildcommands/builders/cleanup.py +35 -0
- wl_cli/commands/buildcommands/builders/coordinator.py +122 -0
- wl_cli/commands/buildcommands/builders/environment.py +81 -0
- wl_cli/commands/buildcommands/builders/rust_builder.py +39 -0
- wl_cli/commands/buildcommands/builders/stubs.py +58 -0
- wl_cli/commands/buildcommands/dist.py +326 -0
- wl_cli/commands/buildcommands/test.py +89 -0
- wl_cli/commands/clean/__init__.py +1 -0
- wl_cli/commands/clean/build.py +151 -0
- wl_cli/commands/clean/clean.py +294 -0
- wl_cli/commands/clean/clean_utils.py +77 -0
- wl_cli/commands/clean/core.py +236 -0
- wl_cli/commands/clean/dead_code/__init__.py +0 -0
- wl_cli/commands/clean/dead_code/dead_code_command.py +70 -0
- wl_cli/commands/clean/dead_code/detector.py +161 -0
- wl_cli/commands/clean/dead_code/fixer.py +176 -0
- wl_cli/commands/clean/dead_code/reporter.py +295 -0
- wl_cli/commands/clean/dead_code/utils.py +0 -0
- wl_cli/commands/clean/lfs.py +215 -0
- wl_cli/commands/clean/python.py +81 -0
- wl_cli/commands/clean/rust.py +91 -0
- wl_cli/commands/clean/utils/__init__.py +34 -0
- wl_cli/commands/clean/venv.py +91 -0
- wl_cli/commands/cleanup.py +73 -0
- wl_cli/commands/click_base.py +79 -0
- wl_cli/commands/config/__init__.py +1 -0
- wl_cli/commands/config/config.py +291 -0
- wl_cli/commands/debug/__init__.py +6 -0
- wl_cli/commands/debug/debug.py +309 -0
- wl_cli/commands/debug/debug_cache.py +86 -0
- wl_cli/commands/debug/debug_subagent.py +156 -0
- wl_cli/commands/debug/output_formatter.py +165 -0
- wl_cli/commands/debug/source_hasher.py +92 -0
- wl_cli/commands/format/__init__.py +13 -0
- wl_cli/commands/format/format_cache_adapter.py +125 -0
- wl_cli/commands/format/format_command.py +197 -0
- wl_cli/commands/format/format_coordinator.py +191 -0
- wl_cli/commands/format/format_executor.py +470 -0
- wl_cli/commands/format/format_outcome.py +44 -0
- wl_cli/commands/format/format_path_handler.py +1016 -0
- wl_cli/commands/format/format_progress.py +62 -0
- wl_cli/commands/format/format_reporter.py +31 -0
- wl_cli/commands/format/python_formatter.py +506 -0
- wl_cli/commands/format/rust_formatter.py +106 -0
- wl_cli/commands/gate/__init__.py +1 -0
- wl_cli/commands/gate/gate_command.py +862 -0
- wl_cli/commands/gate/preflight.py +445 -0
- wl_cli/commands/git/__init__.py +1 -0
- wl_cli/commands/git/config.py +169 -0
- wl_cli/commands/git/git_facts.py +60 -0
- wl_cli/commands/git/git_flow.py +86 -0
- wl_cli/commands/git/hook.py +112 -0
- wl_cli/commands/git/policy.py +216 -0
- wl_cli/commands/git/push_update.py +82 -0
- wl_cli/commands/initenv/__init__.py +1 -0
- wl_cli/commands/initenv/common/__init__.py +23 -0
- wl_cli/commands/initenv/common/check_git_bash.py +78 -0
- wl_cli/commands/initenv/common/error_handler.py +68 -0
- wl_cli/commands/initenv/common/exceptions.py +52 -0
- wl_cli/commands/initenv/components/__init__.py +4 -0
- wl_cli/commands/initenv/components/cargo_sync.py +240 -0
- wl_cli/commands/initenv/components/config_manager.py +106 -0
- wl_cli/commands/initenv/components/directory_utils.py +71 -0
- wl_cli/commands/initenv/components/git/__init__.py +9 -0
- wl_cli/commands/initenv/components/git/branch_creator.py +143 -0
- wl_cli/commands/initenv/components/git/git_flow_interface.py +24 -0
- wl_cli/commands/initenv/components/git/git_flow_manager.py +159 -0
- wl_cli/commands/initenv/components/git/git_lfs_manager.py +272 -0
- wl_cli/commands/initenv/components/git/git_utility.py +254 -0
- wl_cli/commands/initenv/components/git/gitignore_manager.py +53 -0
- wl_cli/commands/initenv/components/git_initializer.py +212 -0
- wl_cli/commands/initenv/components/i18n_manager.py +104 -0
- wl_cli/commands/initenv/components/log_manager.py +241 -0
- wl_cli/commands/initenv/components/project_structure/__init__.py +23 -0
- wl_cli/commands/initenv/components/project_structure/config_generator.py +360 -0
- wl_cli/commands/initenv/components/project_structure/directory_creator.py +184 -0
- wl_cli/commands/initenv/components/project_structure/hook_source.py +110 -0
- wl_cli/commands/initenv/components/project_structure/hooks_manager.py +995 -0
- wl_cli/commands/initenv/components/project_structure/readme_handler.py +56 -0
- wl_cli/commands/initenv/components/project_structure/rust_files_handler.py +30 -0
- wl_cli/commands/initenv/components/project_structure/setup_handler.py +103 -0
- wl_cli/commands/initenv/components/project_structure/sop_generator.py +73 -0
- wl_cli/commands/initenv/components/project_structure/template_copier.py +104 -0
- wl_cli/commands/initenv/components/project_structure/template_manager.py +195 -0
- wl_cli/commands/initenv/components/pyproject_generator.py +194 -0
- wl_cli/commands/initenv/components/rust_initializer.py +145 -0
- wl_cli/commands/initenv/components/symlink_cleaner.py +99 -0
- wl_cli/commands/initenv/components/symlink_manager.py +52 -0
- wl_cli/commands/initenv/components/venv_manager.py +118 -0
- wl_cli/commands/initenv/initenv.py +169 -0
- wl_cli/commands/initenv/services/__init__.py +11 -0
- wl_cli/commands/initenv/services/environment_initializer.py +288 -0
- wl_cli/commands/initenv/services/git_lfs_initializer.py +26 -0
- wl_cli/commands/initenv/services/project_structure_initializer.py +52 -0
- wl_cli/commands/lfs/README.md +221 -0
- wl_cli/commands/lfs/__init__.py +5 -0
- wl_cli/commands/lfs/cli.py +106 -0
- wl_cli/commands/lfs/config.py +164 -0
- wl_cli/commands/lfs/hook.py +61 -0
- wl_cli/commands/lfs/initializer.py +531 -0
- wl_cli/commands/lfs/manager.py +95 -0
- wl_cli/commands/lfs/policy.py +165 -0
- wl_cli/commands/lfs/watcher.py +294 -0
- wl_cli/commands/lint/__init__.py +1 -0
- wl_cli/commands/lint/lint_command.py +297 -0
- wl_cli/commands/lint/lint_executor.py +409 -0
- wl_cli/commands/lint/lint_reporter.py +579 -0
- wl_cli/commands/lint/lint_run.py +258 -0
- wl_cli/commands/lint/mypy_config.py +90 -0
- wl_cli/commands/registry.py +103 -0
- wl_cli/commands/self/__init__.py +7 -0
- wl_cli/commands/self/common/__init__.py +8 -0
- wl_cli/commands/self/common/capabilities.py +30 -0
- wl_cli/commands/self/common/config.py +27 -0
- wl_cli/commands/self/common/version_cache.py +85 -0
- wl_cli/commands/self/handlers/__init__.py +19 -0
- wl_cli/commands/self/handlers/base_handler.py +28 -0
- wl_cli/commands/self/handlers/install_handler.py +85 -0
- wl_cli/commands/self/handlers/status_handler.py +66 -0
- wl_cli/commands/self/handlers/uninstall_handler.py +58 -0
- wl_cli/commands/self/handlers/update_handler.py +102 -0
- wl_cli/commands/self/handlers/version_handler.py +16 -0
- wl_cli/commands/self/self_command.py +237 -0
- wl_cli/commands/self/services/__init__.py +15 -0
- wl_cli/commands/self/services/installation_manager.py +187 -0
- wl_cli/commands/self/services/local_installer.py +165 -0
- wl_cli/commands/self/services/pypi_updater.py +278 -0
- wl_cli/commands/self/services/windows_update.py +174 -0
- wl_cli/commands/testcommands/__init__.py +8 -0
- wl_cli/commands/testcommands/base_dependency_analyzer.py +198 -0
- wl_cli/commands/testcommands/batch_processor.py +278 -0
- wl_cli/commands/testcommands/cache_manager.py +1156 -0
- wl_cli/commands/testcommands/coverage_analyzer.py +955 -0
- wl_cli/commands/testcommands/coverage_cache_manager.py +183 -0
- wl_cli/commands/testcommands/progress_manager.py +79 -0
- wl_cli/commands/testcommands/python_env_detector.py +207 -0
- wl_cli/commands/testcommands/report_generator.py +101 -0
- wl_cli/commands/testcommands/single_test_executor.py +250 -0
- wl_cli/commands/testcommands/speed_checker.py +118 -0
- wl_cli/commands/testcommands/test_command_builder.py +165 -0
- wl_cli/commands/testcommands/test_commands.py +786 -0
- wl_cli/commands/testcommands/test_reporter.py +181 -0
- wl_cli/commands/testcommands/test_result_handler.py +96 -0
- wl_cli/commands/testcommands/test_runner.py +1343 -0
- wl_cli/commands/testcommands/test_utils.py +197 -0
- wl_cli/commands/testcommands/utils/__init__.py +17 -0
- wl_cli/commands/testcommands/utils/coverage_parser.py +98 -0
- wl_cli/commands/testcommands/utils/env_info.py +36 -0
- wl_cli/commands/testcommands/utils/junit_parser.py +75 -0
- wl_cli/commands/testcommands/utils/markdown_utils.py +20 -0
- wl_cli/commands/testcommands/utils/project_root.py +61 -0
- wl_cli/commands/update/__init__.py +9 -0
- wl_cli/commands/update/services/__init__.py +21 -0
- wl_cli/commands/update/services/backup_manager.py +207 -0
- wl_cli/commands/update/services/component_manager.py +83 -0
- wl_cli/commands/update/services/conflict_resolver.py +189 -0
- wl_cli/commands/update/services/vendors_updater.py +85 -0
- wl_cli/commands/update/services/version_tracker.py +127 -0
- wl_cli/commands/update/update_command.py +270 -0
- wl_cli/commands/update/utils/__init__.py +3 -0
- wl_cli/commands/version/__init__.py +9 -0
- wl_cli/commands/version/version_command.py +155 -0
- wl_cli/commands/workflow.py +477 -0
- wl_cli/env/__init__.py +5 -0
- wl_cli/env/cli.py +167 -0
- wl_cli/env_status.py +157 -0
- wl_cli/envelope.py +91 -0
- wl_cli/exceptions.py +85 -0
- wl_cli/lib/__init__.py +3 -0
- wl_cli/lib/rust_utils.py +35 -0
- wl_cli/mcp/__init__.py +6 -0
- wl_cli/mcp/capabilities.py +19 -0
- wl_cli/mcp/cli.py +22 -0
- wl_cli/mcp/gitlab.py +553 -0
- wl_cli/mcp/k8s.py +344 -0
- wl_cli/mcp/protocol.py +159 -0
- wl_cli/platform.py +139 -0
- wl_cli/quality/__init__.py +18 -0
- wl_cli/utils/__init__.py +7 -0
- wl_cli/utils/cache.py +491 -0
- wl_cli/utils/cache_ledger.py +355 -0
- wl_cli/utils/cache_store.py +546 -0
- wl_cli/utils/config/__init__.py +27 -0
- wl_cli/utils/config/config_loader.py +163 -0
- wl_cli/utils/config/core.py +862 -0
- wl_cli/utils/config/defaults.py +142 -0
- wl_cli/utils/config/env_exporter.py +86 -0
- wl_cli/utils/config/env_parser.py +108 -0
- wl_cli/utils/config/validation.py +280 -0
- wl_cli/utils/error_handler.py +165 -0
- wl_cli/utils/file_copier.py +56 -0
- wl_cli/utils/file_operations.py +506 -0
- wl_cli/utils/language_utils.py +122 -0
- wl_cli/utils/lazy_import.py +240 -0
- wl_cli/utils/log_levels.py +35 -0
- wl_cli/utils/log_rotators.py +74 -0
- wl_cli/utils/logging.py +458 -0
- wl_cli/utils/output_context.py +142 -0
- wl_cli/utils/performance/__init__.py +1 -0
- wl_cli/utils/performance/decorators.py +111 -0
- wl_cli/utils/performance/exporter.py +38 -0
- wl_cli/utils/performance/models.py +16 -0
- wl_cli/utils/performance/monitor.py +161 -0
- wl_cli/utils/performance_monitor.py +32 -0
- wl_cli/utils/platform_adapter.py +131 -0
- wl_cli/utils/pre_commit.py +266 -0
- wl_cli/utils/pre_commit_config.py +72 -0
- wl_cli/utils/root.py +521 -0
- wl_cli/utils/root_fallback.py +256 -0
- wl_cli/utils/run_evidence.py +236 -0
- wl_cli/utils/structured_logger.py +18 -0
- wl_cli/utils/structured_logging/__init__.py +19 -0
- wl_cli/utils/structured_logging/config.py +337 -0
- wl_cli/utils/structured_logging/core.py +177 -0
- wl_cli/utils/structured_logging/env.py +56 -0
- wl_cli/utils/structured_logging/filtering.py +75 -0
- wl_cli/utils/structured_logging/filters.py +55 -0
- wl_cli/utils/structured_logging/formatters.py +251 -0
- wl_cli/utils/structured_logging/handlers.py +308 -0
- wl_cli/utils/structured_logging/logger.py +354 -0
- wl_cli/utils/subprocess.py +71 -0
- wl_cli/utils/subprocess_utils.py +260 -0
- wl_cli/utils/test_utils/__init__.py +5 -0
- wl_cli/utils/test_utils/test_filter.py +36 -0
- wl_cli/utils/uv_run.py +79 -0
- wl_cli/utils/uv_tool.py +117 -0
- wl_cli/utils/uv_tree.py +71 -0
- wl_cli/utils/uv_workspace.py +174 -0
- wl_cli/utils/version/__init__.py +15 -0
- wl_cli/utils/version/pypi_version_checker.py +95 -0
- wl_cli/utils/version/version_comparator.py +133 -0
- wl_cli/utils/version/version_detectors.py +312 -0
- wl_cli/utils/version/version_service.py +131 -0
- wl_cli/utils/version/version_updater.py +198 -0
- wl_cli/utils/wl_dir_updater.py +1440 -0
- wl_cli/utils/workspace_detector/__init__.py +28 -0
- wl_cli/utils/workspace_detector/core.py +161 -0
- wl_cli/utils/workspace_detector/detection_strategies.py +107 -0
- wl_cli/utils/workspace_detector/exceptions.py +5 -0
- wl_cli/utils/workspace_detector/types.py +17 -0
- wl_cli/utils/workspace_detector/venv_resolver.py +84 -0
- wl_cli/vendors/config/.codespellrc +2 -0
- wl_cli/vendors/config/dependencies.toml +10 -0
- wl_cli/vendors/config/mypy.ini +62 -0
- wl_cli/vendors/config/pyproject_defaults.toml +28 -0
- wl_cli/vendors/config/template_config.toml +24 -0
- wl_cli/vendors/config/tool_configs.toml +76 -0
- wl_cli/vendors/git/.gitignore +122 -0
- wl_cli/vendors/git/.pre-commit-config.yaml +37 -0
- wl_cli/vendors/hooks/applypatch-msg.sample +15 -0
- wl_cli/vendors/hooks/commit-msg.sample +24 -0
- wl_cli/vendors/hooks/fsmonitor-watchman.sample +174 -0
- wl_cli/vendors/hooks/post-update.sample +8 -0
- wl_cli/vendors/hooks/pre-applypatch.sample +14 -0
- wl_cli/vendors/hooks/pre-commit +45 -0
- wl_cli/vendors/hooks/pre-commit.legacy +31 -0
- wl_cli/vendors/hooks/pre-commit.sample +49 -0
- wl_cli/vendors/hooks/pre-merge-commit.sample +13 -0
- wl_cli/vendors/hooks/pre-push.sample +60 -0
- wl_cli/vendors/hooks/pre-rebase.sample +169 -0
- wl_cli/vendors/hooks/pre-receive.sample +24 -0
- wl_cli/vendors/hooks/prepare-commit-msg.sample +42 -0
- wl_cli/vendors/hooks/push-to-checkout.sample +78 -0
- wl_cli/vendors/hooks/sendemail-validate.sample +77 -0
- wl_cli/vendors/hooks/unix/applypatch-msg.sample +15 -0
- wl_cli/vendors/hooks/unix/check_lockfile.py +58 -0
- wl_cli/vendors/hooks/unix/check_lockfile.sh +36 -0
- wl_cli/vendors/hooks/unix/commit-msg.sample +24 -0
- wl_cli/vendors/hooks/unix/fsmonitor-watchman.sample +174 -0
- wl_cli/vendors/hooks/unix/post-update.sample +8 -0
- wl_cli/vendors/hooks/unix/pre-applypatch.sample +14 -0
- wl_cli/vendors/hooks/unix/pre-commit +190 -0
- wl_cli/vendors/hooks/unix/pre-commit.legacy +31 -0
- wl_cli/vendors/hooks/unix/pre-commit.py +81 -0
- wl_cli/vendors/hooks/unix/pre-commit.sample +49 -0
- wl_cli/vendors/hooks/unix/pre-merge-commit.sample +13 -0
- wl_cli/vendors/hooks/unix/pre-push +417 -0
- wl_cli/vendors/hooks/unix/pre-push.sample +53 -0
- wl_cli/vendors/hooks/unix/pre-rebase.sample +169 -0
- wl_cli/vendors/hooks/unix/pre-receive.sample +24 -0
- wl_cli/vendors/hooks/unix/prepare-commit-msg.sample +42 -0
- wl_cli/vendors/hooks/update.sample +128 -0
- wl_cli/vendors/hooks/win/work.bat +63 -0
- wl_cli/vendors/project/.gitignore +90 -0
- wl_cli/vendors/project/.python-version +1 -0
- wl_cli/vendors/project/LICENSE +21 -0
- wl_cli/vendors/project/README.md +0 -0
- wl_cli/vendors/project/pyproject.toml +27 -0
- wl_cli/vendors/project/pyproject_no_workspace.toml +16 -0
- wl_cli/vendors/project/pyproject_workspace.toml +14 -0
- wl_cli/vendors/readme/README.md +120 -0
- wl_cli/vendors/rust/Cargo.toml +14 -0
- wl_cli/vendors/rust/lib/__init__.py +3 -0
- wl_cli/vendors/rust/lib/rust_utils.py +31 -0
- wl_cli/vendors/rust/src/lib.rs +13 -0
- wl_cli/vendors/rust/src/main.rs +3 -0
- wl_cli/vendors/rust/tests/test_rust_fallback.py +40 -0
- wl_cli/vendors/sop_doc/git-dev-sop.md +220 -0
- wl_cli/vendors/sop_doc/industrial-standard-sop.md +145 -0
- wl_cli/vendors/sop_doc/python-sop.md +342 -0
- wl_cli/vendors/sop_doc/rust-readme.md +219 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""Performance monitoring decorators and utilities."""
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from .monitor import PerformanceMonitor
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def monitor_performance(operation_name: str, **additional_data: Any):
|
|
12
|
+
"""
|
|
13
|
+
Decorator for monitoring the performance of a function.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
operation_name: Name of the operation to track
|
|
17
|
+
**additional_data: Additional data to store with the metrics
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def decorator(func: Callable) -> Callable:
|
|
21
|
+
@functools.wraps(func)
|
|
22
|
+
def wrapper(*args, **kwargs):
|
|
23
|
+
monitor = get_performance_monitor()
|
|
24
|
+
with monitor.monitor_operation(operation_name, **additional_data):
|
|
25
|
+
return func(*args, **kwargs)
|
|
26
|
+
|
|
27
|
+
return wrapper
|
|
28
|
+
|
|
29
|
+
return decorator
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# Global monitor instance
|
|
33
|
+
_performance_monitor = PerformanceMonitor()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_performance_monitor() -> PerformanceMonitor:
|
|
37
|
+
"""
|
|
38
|
+
Get the global performance monitor instance.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
The global performance monitor instance
|
|
42
|
+
"""
|
|
43
|
+
return _performance_monitor
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def start_operation(operation_name: str) -> None:
|
|
47
|
+
"""
|
|
48
|
+
Start timing an operation using the global monitor.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
operation_name: Name of the operation to track
|
|
52
|
+
"""
|
|
53
|
+
_performance_monitor.start_operation(operation_name)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def end_operation(
|
|
57
|
+
operation_name: str, success: bool = True, **additional_data: Any
|
|
58
|
+
) -> Any:
|
|
59
|
+
"""
|
|
60
|
+
End timing an operation and record metrics using the global monitor.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
operation_name: Name of the operation to track
|
|
64
|
+
success: Whether the operation was successful
|
|
65
|
+
**additional_data: Additional data to store with the metrics
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
PerformanceMetrics object with the recorded metrics
|
|
69
|
+
"""
|
|
70
|
+
return _performance_monitor.end_operation(
|
|
71
|
+
operation_name, success, **additional_data
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def monitor_operation(operation_name: str, **additional_data: Any):
|
|
76
|
+
"""
|
|
77
|
+
Context manager for monitoring an operation using the global monitor.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
operation_name: Name of the operation to track
|
|
81
|
+
**additional_data: Additional data to store with the metrics
|
|
82
|
+
"""
|
|
83
|
+
return _performance_monitor.monitor_operation(operation_name, **additional_data)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def get_metrics() -> list[Any]:
|
|
87
|
+
"""
|
|
88
|
+
Get all recorded metrics from the global monitor.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
List of PerformanceMetrics objects
|
|
92
|
+
"""
|
|
93
|
+
return _performance_monitor.get_metrics()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def clear_metrics() -> None:
|
|
97
|
+
"""Clear all recorded metrics from the global monitor."""
|
|
98
|
+
_performance_monitor.clear_metrics()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def export_metrics(file_path: Path) -> None:
|
|
102
|
+
"""
|
|
103
|
+
Export metrics to a JSON file using the global monitor.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
file_path: Path to the output file
|
|
107
|
+
"""
|
|
108
|
+
from .exporter import MetricsExporter
|
|
109
|
+
|
|
110
|
+
metrics = _performance_monitor.get_metrics()
|
|
111
|
+
MetricsExporter.export_to_json(metrics, file_path)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Performance metrics export functionality."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from .models import PerformanceMetrics
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MetricsExporter:
|
|
10
|
+
"""Export performance metrics to various formats."""
|
|
11
|
+
|
|
12
|
+
@staticmethod
|
|
13
|
+
def export_to_json(metrics: list[PerformanceMetrics], file_path: Path) -> None:
|
|
14
|
+
"""
|
|
15
|
+
Export metrics to a JSON file.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
metrics: List of PerformanceMetrics objects
|
|
19
|
+
file_path: Path to the output file
|
|
20
|
+
"""
|
|
21
|
+
try:
|
|
22
|
+
metrics_data = [
|
|
23
|
+
{
|
|
24
|
+
"operation_name": metric.operation_name,
|
|
25
|
+
"execution_time": metric.execution_time,
|
|
26
|
+
"start_time": metric.start_time,
|
|
27
|
+
"end_time": metric.end_time,
|
|
28
|
+
"success": metric.success,
|
|
29
|
+
"additional_data": metric.additional_data,
|
|
30
|
+
}
|
|
31
|
+
for metric in metrics
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
with open(file_path, "w", encoding="utf-8") as f:
|
|
35
|
+
json.dump(metrics_data, f, indent=2, ensure_ascii=False)
|
|
36
|
+
except (OSError, TypeError) as e:
|
|
37
|
+
# Handle file I/O errors and JSON serialization errors
|
|
38
|
+
raise OSError(f"Failed to export metrics to {file_path}: {e}")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Performance monitoring data models."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class PerformanceMetrics:
|
|
9
|
+
"""Performance metrics for a single operation."""
|
|
10
|
+
|
|
11
|
+
operation_name: str
|
|
12
|
+
execution_time: float
|
|
13
|
+
start_time: float
|
|
14
|
+
end_time: float
|
|
15
|
+
success: bool
|
|
16
|
+
additional_data: dict[str, Any] = field(default_factory=dict)
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""Core performance monitoring functionality."""
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from contextlib import contextmanager
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from .models import PerformanceMetrics
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PerformanceMonitor:
|
|
12
|
+
"""A utility class for monitoring performance of operations."""
|
|
13
|
+
|
|
14
|
+
def __init__(self):
|
|
15
|
+
self._metrics: list[PerformanceMetrics] = []
|
|
16
|
+
self._active_operations: dict[str, float] = {}
|
|
17
|
+
|
|
18
|
+
def start_operation(self, operation_name: str) -> None:
|
|
19
|
+
"""
|
|
20
|
+
Start timing an operation.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
operation_name: Name of the operation to track
|
|
24
|
+
"""
|
|
25
|
+
self._active_operations[operation_name] = time.perf_counter()
|
|
26
|
+
|
|
27
|
+
def end_operation(
|
|
28
|
+
self, operation_name: str, success: bool = True, **additional_data: Any
|
|
29
|
+
) -> PerformanceMetrics:
|
|
30
|
+
"""
|
|
31
|
+
End timing an operation and record metrics.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
operation_name: Name of the operation to track
|
|
35
|
+
success: Whether the operation was successful
|
|
36
|
+
**additional_data: Additional data to store with the metrics
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
PerformanceMetrics object with the recorded metrics
|
|
40
|
+
"""
|
|
41
|
+
if operation_name not in self._active_operations:
|
|
42
|
+
raise ValueError(f"Operation '{operation_name}' was not started")
|
|
43
|
+
|
|
44
|
+
start_time = self._active_operations.pop(operation_name)
|
|
45
|
+
end_time = time.perf_counter()
|
|
46
|
+
execution_time = end_time - start_time
|
|
47
|
+
|
|
48
|
+
metrics = PerformanceMetrics(
|
|
49
|
+
operation_name=operation_name,
|
|
50
|
+
execution_time=execution_time,
|
|
51
|
+
start_time=start_time,
|
|
52
|
+
end_time=end_time,
|
|
53
|
+
success=success,
|
|
54
|
+
additional_data=additional_data,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
self._metrics.append(metrics)
|
|
58
|
+
return metrics
|
|
59
|
+
|
|
60
|
+
def record_operation(
|
|
61
|
+
self,
|
|
62
|
+
operation_name: str,
|
|
63
|
+
execution_time: float,
|
|
64
|
+
success: bool = True,
|
|
65
|
+
**additional_data: Any,
|
|
66
|
+
) -> PerformanceMetrics:
|
|
67
|
+
"""
|
|
68
|
+
Record metrics for an operation without timing it.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
operation_name: Name of the operation to track
|
|
72
|
+
execution_time: Execution time in seconds
|
|
73
|
+
success: Whether the operation was successful
|
|
74
|
+
**additional_data: Additional data to store with the metrics
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
PerformanceMetrics object with the recorded metrics
|
|
78
|
+
"""
|
|
79
|
+
start_time = time.perf_counter() - execution_time
|
|
80
|
+
end_time = start_time + execution_time
|
|
81
|
+
|
|
82
|
+
metrics = PerformanceMetrics(
|
|
83
|
+
operation_name=operation_name,
|
|
84
|
+
execution_time=execution_time,
|
|
85
|
+
start_time=start_time,
|
|
86
|
+
end_time=end_time,
|
|
87
|
+
success=success,
|
|
88
|
+
additional_data=additional_data,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
self._metrics.append(metrics)
|
|
92
|
+
return metrics
|
|
93
|
+
|
|
94
|
+
@contextmanager
|
|
95
|
+
def monitor_operation(self, operation_name: str, **additional_data: Any):
|
|
96
|
+
"""
|
|
97
|
+
Context manager for monitoring an operation.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
operation_name: Name of the operation to track
|
|
101
|
+
**additional_data: Additional data to store with the metrics
|
|
102
|
+
"""
|
|
103
|
+
self.start_operation(operation_name)
|
|
104
|
+
success = True
|
|
105
|
+
try:
|
|
106
|
+
yield
|
|
107
|
+
except Exception:
|
|
108
|
+
success = False
|
|
109
|
+
raise
|
|
110
|
+
finally:
|
|
111
|
+
try:
|
|
112
|
+
self.end_operation(operation_name, success, **additional_data)
|
|
113
|
+
except ValueError:
|
|
114
|
+
# Operation was not started, ignore
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
def get_metrics(self) -> list[PerformanceMetrics]:
|
|
118
|
+
"""
|
|
119
|
+
Get all recorded metrics.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
List of PerformanceMetrics objects
|
|
123
|
+
"""
|
|
124
|
+
return self._metrics.copy()
|
|
125
|
+
|
|
126
|
+
def get_average_execution_time(self, operation_name: str) -> float | None:
|
|
127
|
+
"""
|
|
128
|
+
Get the average execution time for an operation.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
operation_name: Name of the operation
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Average execution time in seconds, or None if no metrics found
|
|
135
|
+
"""
|
|
136
|
+
times = [
|
|
137
|
+
metric.execution_time
|
|
138
|
+
for metric in self._metrics
|
|
139
|
+
if metric.operation_name == operation_name
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
if not times:
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
return sum(times) / len(times)
|
|
146
|
+
|
|
147
|
+
def clear_metrics(self) -> None:
|
|
148
|
+
"""Clear all recorded metrics."""
|
|
149
|
+
self._metrics.clear()
|
|
150
|
+
self._active_operations.clear()
|
|
151
|
+
|
|
152
|
+
def export_metrics(self, file_path: Path) -> None:
|
|
153
|
+
"""
|
|
154
|
+
Export metrics to a JSON file.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
file_path: Path to the output file
|
|
158
|
+
"""
|
|
159
|
+
from .exporter import MetricsExporter
|
|
160
|
+
|
|
161
|
+
MetricsExporter.export_to_json(self._metrics, file_path)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Performance monitoring utilities for WL Commands.
|
|
2
|
+
|
|
3
|
+
This module serves as the entry point for the modularized performance monitoring functionality.
|
|
4
|
+
主要功能委托给专门的模块以获得更好的组织结构。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .performance.decorators import (
|
|
8
|
+
clear_metrics,
|
|
9
|
+
end_operation,
|
|
10
|
+
export_metrics,
|
|
11
|
+
get_metrics,
|
|
12
|
+
get_performance_monitor,
|
|
13
|
+
monitor_operation,
|
|
14
|
+
monitor_performance,
|
|
15
|
+
start_operation,
|
|
16
|
+
)
|
|
17
|
+
from .performance.models import PerformanceMetrics
|
|
18
|
+
from .performance.monitor import PerformanceMonitor
|
|
19
|
+
|
|
20
|
+
# Backward compatibility: re-export all the main components
|
|
21
|
+
__all__ = [
|
|
22
|
+
"PerformanceMetrics",
|
|
23
|
+
"PerformanceMonitor",
|
|
24
|
+
"monitor_performance",
|
|
25
|
+
"get_performance_monitor",
|
|
26
|
+
"start_operation",
|
|
27
|
+
"end_operation",
|
|
28
|
+
"monitor_operation",
|
|
29
|
+
"get_metrics",
|
|
30
|
+
"clear_metrics",
|
|
31
|
+
"export_metrics",
|
|
32
|
+
]
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""Platform adapter utility."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import platform
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PlatformAdapter:
|
|
9
|
+
"""Platform adapter for Windows and Unix-like systems."""
|
|
10
|
+
|
|
11
|
+
def __init__(self) -> None:
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def get_system() -> str:
|
|
16
|
+
"""Get the current system name."""
|
|
17
|
+
return platform.system().lower()
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def is_windows() -> bool:
|
|
21
|
+
"""Check if the current system is Windows."""
|
|
22
|
+
return PlatformAdapter.get_system() == "windows"
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def is_linux() -> bool:
|
|
26
|
+
"""Check if the current system is Linux."""
|
|
27
|
+
return PlatformAdapter.get_system() == "linux"
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def is_mac() -> bool:
|
|
31
|
+
"""Check if the current system is macOS."""
|
|
32
|
+
return PlatformAdapter.get_system() == "darwin"
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def get_env() -> dict[str, str]:
|
|
36
|
+
"""Get environment variables for the current platform."""
|
|
37
|
+
env = os.environ.copy()
|
|
38
|
+
|
|
39
|
+
if PlatformAdapter.is_windows():
|
|
40
|
+
env["PYTHONIOENCODING"] = "utf-8"
|
|
41
|
+
env["PYTHONLEGACYWINDOWSFSENCODING"] = "1"
|
|
42
|
+
else:
|
|
43
|
+
env["PYTHONIOENCODING"] = "utf-8"
|
|
44
|
+
|
|
45
|
+
return env
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def get_encoding() -> str:
|
|
49
|
+
"""Get the appropriate encoding for the current platform."""
|
|
50
|
+
if PlatformAdapter.is_windows():
|
|
51
|
+
return "utf-8" if sys.platform.startswith("win") else ""
|
|
52
|
+
return "utf-8"
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
def get_platform_specific_path(path: str) -> str:
|
|
56
|
+
"""
|
|
57
|
+
Get platform-specific path.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
path: Path to convert
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Platform-specific path
|
|
64
|
+
"""
|
|
65
|
+
if PlatformAdapter.is_windows():
|
|
66
|
+
return path.replace("/", "\\")
|
|
67
|
+
return path.replace("\\", "/")
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def get_shell() -> str:
|
|
71
|
+
"""
|
|
72
|
+
Get the default shell for the current platform.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Default shell executable
|
|
76
|
+
"""
|
|
77
|
+
if PlatformAdapter.is_windows():
|
|
78
|
+
return "cmd.exe"
|
|
79
|
+
elif PlatformAdapter.is_mac():
|
|
80
|
+
return "/bin/zsh"
|
|
81
|
+
else: # Linux
|
|
82
|
+
return "/bin/bash"
|
|
83
|
+
|
|
84
|
+
@staticmethod
|
|
85
|
+
def get_line_ending() -> str:
|
|
86
|
+
"""
|
|
87
|
+
Get the line ending for the current platform.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Line ending string
|
|
91
|
+
"""
|
|
92
|
+
if PlatformAdapter.is_windows():
|
|
93
|
+
return "\r\n"
|
|
94
|
+
return "\n"
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def get_venv_create_command(venv_path: str) -> list[str]:
|
|
98
|
+
"""Get the primary command that creates a virtual environment.
|
|
99
|
+
|
|
100
|
+
Windows invokes uv through the running interpreter (``python -m uv``)
|
|
101
|
+
because a bare ``uv`` is not guaranteed to be on ``PATH``; Unix-like
|
|
102
|
+
systems call the ``uv`` command directly.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
venv_path: Destination directory for the virtual environment.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
The argv list for the first creation attempt.
|
|
109
|
+
"""
|
|
110
|
+
if PlatformAdapter.is_windows():
|
|
111
|
+
return [sys.executable, "-m", "uv", "venv", venv_path]
|
|
112
|
+
return ["uv", "venv", venv_path]
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def get_venv_create_fallback_command(venv_path: str) -> list[str] | None:
|
|
116
|
+
"""Get the retry command for virtual environment creation, if any.
|
|
117
|
+
|
|
118
|
+
Only Windows retries: ``python -m uv`` fails with ``No module named
|
|
119
|
+
uv`` when uv is installed as a standalone executable rather than as a
|
|
120
|
+
module, and the retry then calls ``uv`` directly. Unix-like systems
|
|
121
|
+
have no fallback.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
venv_path: Destination directory for the virtual environment.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
The argv list to retry with, or ``None`` when no retry applies.
|
|
128
|
+
"""
|
|
129
|
+
if PlatformAdapter.is_windows():
|
|
130
|
+
return ["uv", "venv", venv_path]
|
|
131
|
+
return None
|