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,240 @@
|
|
|
1
|
+
"""Lazy import utilities for WL Commands."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from typing import Any, Generic, TypeVar
|
|
5
|
+
|
|
6
|
+
T = TypeVar("T")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class LazyImport(Generic[T]):
|
|
10
|
+
"""Lazy import wrapper that defers import until first access."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, module_name: str, attribute_name: str | None = None):
|
|
13
|
+
"""
|
|
14
|
+
Initialize a lazy import.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
module_name: The name of the module to import
|
|
18
|
+
attribute_name: Optional attribute name to import from the module
|
|
19
|
+
"""
|
|
20
|
+
self.module_name = module_name
|
|
21
|
+
self.attribute_name = attribute_name
|
|
22
|
+
self._module: Any | None = None
|
|
23
|
+
self._attribute: T | None = None
|
|
24
|
+
|
|
25
|
+
def _import(self) -> T:
|
|
26
|
+
"""
|
|
27
|
+
Perform the actual import.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
The imported module or attribute
|
|
31
|
+
|
|
32
|
+
Raises:
|
|
33
|
+
ImportError: If the module cannot be imported
|
|
34
|
+
AttributeError: If the attribute cannot be found in the module
|
|
35
|
+
"""
|
|
36
|
+
if self._attribute is None:
|
|
37
|
+
if self.attribute_name:
|
|
38
|
+
# Import specific attribute from module
|
|
39
|
+
module = __import__(self.module_name, fromlist=[self.attribute_name])
|
|
40
|
+
self._module = module
|
|
41
|
+
# This will raise AttributeError if the attribute doesn't exist
|
|
42
|
+
self._attribute = getattr(module, self.attribute_name)
|
|
43
|
+
else:
|
|
44
|
+
# Import entire module
|
|
45
|
+
self._module = __import__(self.module_name)
|
|
46
|
+
# When importing entire module, we cast it to T since T represents the module type
|
|
47
|
+
self._attribute = self._module # type: ignore[assignment]
|
|
48
|
+
return self._attribute # type: ignore[return-value]
|
|
49
|
+
|
|
50
|
+
def __get__(self, instance: Any | None, owner: type | None = None) -> T:
|
|
51
|
+
"""
|
|
52
|
+
Get the imported module or attribute.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
instance: The instance accessing the attribute
|
|
56
|
+
owner: The owner class
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
The imported module or attribute
|
|
60
|
+
"""
|
|
61
|
+
return self._import()
|
|
62
|
+
|
|
63
|
+
def __getattr__(self, name: str) -> Any:
|
|
64
|
+
"""
|
|
65
|
+
Get attribute from the imported module.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
name: The attribute name to get
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
The attribute value
|
|
72
|
+
"""
|
|
73
|
+
module = self._import()
|
|
74
|
+
return getattr(module, name)
|
|
75
|
+
|
|
76
|
+
def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
|
77
|
+
"""
|
|
78
|
+
Allow calling the lazy import as a function if it's callable.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
*args: Positional arguments
|
|
82
|
+
**kwargs: Keyword arguments
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
The result of calling the imported object
|
|
86
|
+
"""
|
|
87
|
+
obj = self._import()
|
|
88
|
+
if callable(obj):
|
|
89
|
+
return obj(*args, **kwargs)
|
|
90
|
+
raise TypeError(
|
|
91
|
+
f"{self.module_name}.{self.attribute_name if self.attribute_name else ''} is not callable"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def __repr__(self) -> str:
|
|
95
|
+
"""
|
|
96
|
+
Return a string representation of the lazy import.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
A string representation
|
|
100
|
+
"""
|
|
101
|
+
if self._attribute is None:
|
|
102
|
+
if self.attribute_name:
|
|
103
|
+
return f"LazyImport({self.module_name}, {self.attribute_name})"
|
|
104
|
+
else:
|
|
105
|
+
return f"LazyImport({self.module_name})"
|
|
106
|
+
return repr(self._attribute)
|
|
107
|
+
|
|
108
|
+
def __str__(self) -> str:
|
|
109
|
+
"""
|
|
110
|
+
Return a string representation of the lazy import.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
A string representation
|
|
114
|
+
"""
|
|
115
|
+
return repr(self)
|
|
116
|
+
|
|
117
|
+
def __bool__(self) -> bool:
|
|
118
|
+
"""
|
|
119
|
+
Boolean representation of the lazy import.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
True if the imported object is truthy
|
|
123
|
+
"""
|
|
124
|
+
return bool(self._import())
|
|
125
|
+
|
|
126
|
+
def __dir__(self) -> list[str]:
|
|
127
|
+
"""
|
|
128
|
+
Directory of attributes for the lazy import.
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
List of attribute names
|
|
132
|
+
"""
|
|
133
|
+
obj = self._import()
|
|
134
|
+
return dir(obj)
|
|
135
|
+
|
|
136
|
+
def __getattribute__(self, name: str) -> Any:
|
|
137
|
+
"""
|
|
138
|
+
Get attribute from the lazy import or the imported object.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
name: The attribute name to get
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
The attribute value
|
|
145
|
+
"""
|
|
146
|
+
# Handle special attributes
|
|
147
|
+
if name in [
|
|
148
|
+
"module_name",
|
|
149
|
+
"attribute_name",
|
|
150
|
+
"_module",
|
|
151
|
+
"_attribute",
|
|
152
|
+
"_import",
|
|
153
|
+
]:
|
|
154
|
+
return super().__getattribute__(name)
|
|
155
|
+
|
|
156
|
+
# For other attributes, trigger import and delegate to the imported object
|
|
157
|
+
try:
|
|
158
|
+
return super().__getattribute__(name)
|
|
159
|
+
except AttributeError:
|
|
160
|
+
# If attribute not found in LazyImport, try the imported object
|
|
161
|
+
obj = self._import()
|
|
162
|
+
return getattr(obj, name)
|
|
163
|
+
|
|
164
|
+
def __instancecheck__(self, instance: Any) -> bool:
|
|
165
|
+
"""
|
|
166
|
+
Instance check for the lazy import.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
instance: The instance to check
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
True if the instance is an instance of the imported type
|
|
173
|
+
"""
|
|
174
|
+
return isinstance(instance, self._import()) # type: ignore[arg-type]
|
|
175
|
+
|
|
176
|
+
def __subclasscheck__(self, subclass: type) -> bool:
|
|
177
|
+
"""
|
|
178
|
+
Subclass check for the lazy import.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
subclass: The subclass to check
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
True if the subclass is a subclass of the imported type
|
|
185
|
+
"""
|
|
186
|
+
return issubclass(subclass, self._import()) # type: ignore[arg-type]
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def lazy_import(module_name: str, attribute_name: str | None = None) -> LazyImport:
|
|
190
|
+
"""
|
|
191
|
+
Create a lazy import for a module or attribute.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
module_name: The name of the module to import
|
|
195
|
+
attribute_name: Optional attribute name to import from the module
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
A LazyImport instance that will import when first accessed
|
|
199
|
+
"""
|
|
200
|
+
return LazyImport(module_name, attribute_name)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def lazy_imports(**imports: str) -> Callable:
|
|
204
|
+
"""
|
|
205
|
+
Decorator to lazy import multiple modules or attributes.
|
|
206
|
+
|
|
207
|
+
Usage:
|
|
208
|
+
@lazy_imports(
|
|
209
|
+
os='os',
|
|
210
|
+
Path='pathlib.Path',
|
|
211
|
+
json_loads='json.loads'
|
|
212
|
+
)
|
|
213
|
+
class MyClass:
|
|
214
|
+
def method(self):
|
|
215
|
+
return self.os.path.exists('file.txt')
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
**imports: Dictionary of attribute names to import specifications
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
A decorator that adds lazy imports as class attributes
|
|
222
|
+
"""
|
|
223
|
+
|
|
224
|
+
def decorator(cls: type) -> type:
|
|
225
|
+
for attr_name, import_spec in imports.items():
|
|
226
|
+
if "." in import_spec:
|
|
227
|
+
# Handle attribute imports like 'module.attribute'
|
|
228
|
+
parts = import_spec.rsplit(".", 1)
|
|
229
|
+
if len(parts) == 2:
|
|
230
|
+
module_name, attr = parts
|
|
231
|
+
setattr(cls, attr_name, LazyImport(module_name, attr))
|
|
232
|
+
else:
|
|
233
|
+
# Handle module imports
|
|
234
|
+
setattr(cls, attr_name, LazyImport(import_spec))
|
|
235
|
+
else:
|
|
236
|
+
# Handle module imports
|
|
237
|
+
setattr(cls, attr_name, LazyImport(import_spec))
|
|
238
|
+
return cls
|
|
239
|
+
|
|
240
|
+
return decorator
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Log level definitions for WL Commands.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import ClassVar
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LogLevel:
|
|
9
|
+
"""Log levels."""
|
|
10
|
+
|
|
11
|
+
DEBUG = 10
|
|
12
|
+
INFO = 20
|
|
13
|
+
WARNING = 30
|
|
14
|
+
ERROR = 40
|
|
15
|
+
CRITICAL = 50
|
|
16
|
+
|
|
17
|
+
_level_names: ClassVar[dict[int, str]] = {
|
|
18
|
+
DEBUG: "DEBUG",
|
|
19
|
+
INFO: "INFO",
|
|
20
|
+
WARNING: "WARNING",
|
|
21
|
+
ERROR: "ERROR",
|
|
22
|
+
CRITICAL: "CRITICAL",
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def get_name(cls, level: int) -> str:
|
|
27
|
+
"""Get the name of a log level from its value.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
level: The numeric log level value.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
The name of the log level, or "INFO" if unknown.
|
|
34
|
+
"""
|
|
35
|
+
return cls._level_names.get(level, "INFO")
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Log rotation utilities for WL Commands.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import time
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class LogRotator:
|
|
10
|
+
"""Enhanced log rotator that supports size-based and time-based rotation."""
|
|
11
|
+
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
filename: str,
|
|
15
|
+
max_size: int = 10 * 1024 * 1024, # 10MB default
|
|
16
|
+
max_backups: int = 5, # Keep up to 5 backup files
|
|
17
|
+
rotate_days: int = 7, # Rotate after 7 days
|
|
18
|
+
) -> None:
|
|
19
|
+
"""
|
|
20
|
+
Initialize log rotator.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
filename (str): Log file name.
|
|
24
|
+
max_size (int): Maximum file size in bytes before rotation.
|
|
25
|
+
max_backups (int): Maximum number of backup files to keep.
|
|
26
|
+
rotate_days (int): Number of days before rotating the log file.
|
|
27
|
+
"""
|
|
28
|
+
self.filename = filename
|
|
29
|
+
self.max_size = max_size
|
|
30
|
+
self.max_backups = max_backups
|
|
31
|
+
self.rotate_days = rotate_days
|
|
32
|
+
|
|
33
|
+
def should_rotate(self) -> bool:
|
|
34
|
+
"""Check if log file should be rotated based on size or time."""
|
|
35
|
+
try:
|
|
36
|
+
if not os.path.exists(self.filename):
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
# Check size-based rotation
|
|
40
|
+
if os.path.getsize(self.filename) >= self.max_size:
|
|
41
|
+
return True
|
|
42
|
+
|
|
43
|
+
# Check time-based rotation
|
|
44
|
+
file_mtime = os.path.getmtime(self.filename)
|
|
45
|
+
if time.time() - file_mtime >= self.rotate_days * 24 * 60 * 60:
|
|
46
|
+
return True
|
|
47
|
+
|
|
48
|
+
return False
|
|
49
|
+
except OSError:
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
def do_rotate(self) -> None:
|
|
53
|
+
"""Perform log rotation with multiple backup files."""
|
|
54
|
+
try:
|
|
55
|
+
if not os.path.exists(self.filename):
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
# Rotate existing backups
|
|
59
|
+
for i in range(self.max_backups - 1, 0, -1):
|
|
60
|
+
old_backup = f"{self.filename}.{i}"
|
|
61
|
+
new_backup = f"{self.filename}.{i + 1}"
|
|
62
|
+
if os.path.exists(old_backup):
|
|
63
|
+
if os.path.exists(new_backup):
|
|
64
|
+
os.remove(new_backup)
|
|
65
|
+
os.rename(old_backup, new_backup)
|
|
66
|
+
|
|
67
|
+
# Rotate current log file to .1
|
|
68
|
+
first_backup = f"{self.filename}.1"
|
|
69
|
+
if os.path.exists(first_backup):
|
|
70
|
+
os.remove(first_backup)
|
|
71
|
+
os.rename(self.filename, first_backup)
|
|
72
|
+
except OSError:
|
|
73
|
+
# Ignore rotation errors
|
|
74
|
+
pass
|