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.
Files changed (320) hide show
  1. py_wlcli-0.8.0.dist-info/METADATA +139 -0
  2. py_wlcli-0.8.0.dist-info/RECORD +320 -0
  3. py_wlcli-0.8.0.dist-info/WHEEL +4 -0
  4. py_wlcli-0.8.0.dist-info/entry_points.txt +2 -0
  5. py_wlcli-0.8.0.dist-info/licenses/LICENSE +21 -0
  6. wl_cli/__init__.py +27 -0
  7. wl_cli/__main__.py +130 -0
  8. wl_cli/capabilities.py +79 -0
  9. wl_cli/cc/__init__.py +5 -0
  10. wl_cli/cc/checks.py +1019 -0
  11. wl_cli/cc/cli.py +370 -0
  12. wl_cli/cc/mutate.py +1350 -0
  13. wl_cli/cli_click.py +156 -0
  14. wl_cli/commands/__init__.py +84 -0
  15. wl_cli/commands/base.py +80 -0
  16. wl_cli/commands/buildcommands/__init__.py +1 -0
  17. wl_cli/commands/buildcommands/build.py +71 -0
  18. wl_cli/commands/buildcommands/build_utils.py +47 -0
  19. wl_cli/commands/buildcommands/builders/__init__.py +18 -0
  20. wl_cli/commands/buildcommands/builders/cleanup.py +35 -0
  21. wl_cli/commands/buildcommands/builders/coordinator.py +122 -0
  22. wl_cli/commands/buildcommands/builders/environment.py +81 -0
  23. wl_cli/commands/buildcommands/builders/rust_builder.py +39 -0
  24. wl_cli/commands/buildcommands/builders/stubs.py +58 -0
  25. wl_cli/commands/buildcommands/dist.py +326 -0
  26. wl_cli/commands/buildcommands/test.py +89 -0
  27. wl_cli/commands/clean/__init__.py +1 -0
  28. wl_cli/commands/clean/build.py +151 -0
  29. wl_cli/commands/clean/clean.py +294 -0
  30. wl_cli/commands/clean/clean_utils.py +77 -0
  31. wl_cli/commands/clean/core.py +236 -0
  32. wl_cli/commands/clean/dead_code/__init__.py +0 -0
  33. wl_cli/commands/clean/dead_code/dead_code_command.py +70 -0
  34. wl_cli/commands/clean/dead_code/detector.py +161 -0
  35. wl_cli/commands/clean/dead_code/fixer.py +176 -0
  36. wl_cli/commands/clean/dead_code/reporter.py +295 -0
  37. wl_cli/commands/clean/dead_code/utils.py +0 -0
  38. wl_cli/commands/clean/lfs.py +215 -0
  39. wl_cli/commands/clean/python.py +81 -0
  40. wl_cli/commands/clean/rust.py +91 -0
  41. wl_cli/commands/clean/utils/__init__.py +34 -0
  42. wl_cli/commands/clean/venv.py +91 -0
  43. wl_cli/commands/cleanup.py +73 -0
  44. wl_cli/commands/click_base.py +79 -0
  45. wl_cli/commands/config/__init__.py +1 -0
  46. wl_cli/commands/config/config.py +291 -0
  47. wl_cli/commands/debug/__init__.py +6 -0
  48. wl_cli/commands/debug/debug.py +309 -0
  49. wl_cli/commands/debug/debug_cache.py +86 -0
  50. wl_cli/commands/debug/debug_subagent.py +156 -0
  51. wl_cli/commands/debug/output_formatter.py +165 -0
  52. wl_cli/commands/debug/source_hasher.py +92 -0
  53. wl_cli/commands/format/__init__.py +13 -0
  54. wl_cli/commands/format/format_cache_adapter.py +125 -0
  55. wl_cli/commands/format/format_command.py +197 -0
  56. wl_cli/commands/format/format_coordinator.py +191 -0
  57. wl_cli/commands/format/format_executor.py +470 -0
  58. wl_cli/commands/format/format_outcome.py +44 -0
  59. wl_cli/commands/format/format_path_handler.py +1016 -0
  60. wl_cli/commands/format/format_progress.py +62 -0
  61. wl_cli/commands/format/format_reporter.py +31 -0
  62. wl_cli/commands/format/python_formatter.py +506 -0
  63. wl_cli/commands/format/rust_formatter.py +106 -0
  64. wl_cli/commands/gate/__init__.py +1 -0
  65. wl_cli/commands/gate/gate_command.py +862 -0
  66. wl_cli/commands/gate/preflight.py +445 -0
  67. wl_cli/commands/git/__init__.py +1 -0
  68. wl_cli/commands/git/config.py +169 -0
  69. wl_cli/commands/git/git_facts.py +60 -0
  70. wl_cli/commands/git/git_flow.py +86 -0
  71. wl_cli/commands/git/hook.py +112 -0
  72. wl_cli/commands/git/policy.py +216 -0
  73. wl_cli/commands/git/push_update.py +82 -0
  74. wl_cli/commands/initenv/__init__.py +1 -0
  75. wl_cli/commands/initenv/common/__init__.py +23 -0
  76. wl_cli/commands/initenv/common/check_git_bash.py +78 -0
  77. wl_cli/commands/initenv/common/error_handler.py +68 -0
  78. wl_cli/commands/initenv/common/exceptions.py +52 -0
  79. wl_cli/commands/initenv/components/__init__.py +4 -0
  80. wl_cli/commands/initenv/components/cargo_sync.py +240 -0
  81. wl_cli/commands/initenv/components/config_manager.py +106 -0
  82. wl_cli/commands/initenv/components/directory_utils.py +71 -0
  83. wl_cli/commands/initenv/components/git/__init__.py +9 -0
  84. wl_cli/commands/initenv/components/git/branch_creator.py +143 -0
  85. wl_cli/commands/initenv/components/git/git_flow_interface.py +24 -0
  86. wl_cli/commands/initenv/components/git/git_flow_manager.py +159 -0
  87. wl_cli/commands/initenv/components/git/git_lfs_manager.py +272 -0
  88. wl_cli/commands/initenv/components/git/git_utility.py +254 -0
  89. wl_cli/commands/initenv/components/git/gitignore_manager.py +53 -0
  90. wl_cli/commands/initenv/components/git_initializer.py +212 -0
  91. wl_cli/commands/initenv/components/i18n_manager.py +104 -0
  92. wl_cli/commands/initenv/components/log_manager.py +241 -0
  93. wl_cli/commands/initenv/components/project_structure/__init__.py +23 -0
  94. wl_cli/commands/initenv/components/project_structure/config_generator.py +360 -0
  95. wl_cli/commands/initenv/components/project_structure/directory_creator.py +184 -0
  96. wl_cli/commands/initenv/components/project_structure/hook_source.py +110 -0
  97. wl_cli/commands/initenv/components/project_structure/hooks_manager.py +995 -0
  98. wl_cli/commands/initenv/components/project_structure/readme_handler.py +56 -0
  99. wl_cli/commands/initenv/components/project_structure/rust_files_handler.py +30 -0
  100. wl_cli/commands/initenv/components/project_structure/setup_handler.py +103 -0
  101. wl_cli/commands/initenv/components/project_structure/sop_generator.py +73 -0
  102. wl_cli/commands/initenv/components/project_structure/template_copier.py +104 -0
  103. wl_cli/commands/initenv/components/project_structure/template_manager.py +195 -0
  104. wl_cli/commands/initenv/components/pyproject_generator.py +194 -0
  105. wl_cli/commands/initenv/components/rust_initializer.py +145 -0
  106. wl_cli/commands/initenv/components/symlink_cleaner.py +99 -0
  107. wl_cli/commands/initenv/components/symlink_manager.py +52 -0
  108. wl_cli/commands/initenv/components/venv_manager.py +118 -0
  109. wl_cli/commands/initenv/initenv.py +169 -0
  110. wl_cli/commands/initenv/services/__init__.py +11 -0
  111. wl_cli/commands/initenv/services/environment_initializer.py +288 -0
  112. wl_cli/commands/initenv/services/git_lfs_initializer.py +26 -0
  113. wl_cli/commands/initenv/services/project_structure_initializer.py +52 -0
  114. wl_cli/commands/lfs/README.md +221 -0
  115. wl_cli/commands/lfs/__init__.py +5 -0
  116. wl_cli/commands/lfs/cli.py +106 -0
  117. wl_cli/commands/lfs/config.py +164 -0
  118. wl_cli/commands/lfs/hook.py +61 -0
  119. wl_cli/commands/lfs/initializer.py +531 -0
  120. wl_cli/commands/lfs/manager.py +95 -0
  121. wl_cli/commands/lfs/policy.py +165 -0
  122. wl_cli/commands/lfs/watcher.py +294 -0
  123. wl_cli/commands/lint/__init__.py +1 -0
  124. wl_cli/commands/lint/lint_command.py +297 -0
  125. wl_cli/commands/lint/lint_executor.py +409 -0
  126. wl_cli/commands/lint/lint_reporter.py +579 -0
  127. wl_cli/commands/lint/lint_run.py +258 -0
  128. wl_cli/commands/lint/mypy_config.py +90 -0
  129. wl_cli/commands/registry.py +103 -0
  130. wl_cli/commands/self/__init__.py +7 -0
  131. wl_cli/commands/self/common/__init__.py +8 -0
  132. wl_cli/commands/self/common/capabilities.py +30 -0
  133. wl_cli/commands/self/common/config.py +27 -0
  134. wl_cli/commands/self/common/version_cache.py +85 -0
  135. wl_cli/commands/self/handlers/__init__.py +19 -0
  136. wl_cli/commands/self/handlers/base_handler.py +28 -0
  137. wl_cli/commands/self/handlers/install_handler.py +85 -0
  138. wl_cli/commands/self/handlers/status_handler.py +66 -0
  139. wl_cli/commands/self/handlers/uninstall_handler.py +58 -0
  140. wl_cli/commands/self/handlers/update_handler.py +102 -0
  141. wl_cli/commands/self/handlers/version_handler.py +16 -0
  142. wl_cli/commands/self/self_command.py +237 -0
  143. wl_cli/commands/self/services/__init__.py +15 -0
  144. wl_cli/commands/self/services/installation_manager.py +187 -0
  145. wl_cli/commands/self/services/local_installer.py +165 -0
  146. wl_cli/commands/self/services/pypi_updater.py +278 -0
  147. wl_cli/commands/self/services/windows_update.py +174 -0
  148. wl_cli/commands/testcommands/__init__.py +8 -0
  149. wl_cli/commands/testcommands/base_dependency_analyzer.py +198 -0
  150. wl_cli/commands/testcommands/batch_processor.py +278 -0
  151. wl_cli/commands/testcommands/cache_manager.py +1156 -0
  152. wl_cli/commands/testcommands/coverage_analyzer.py +955 -0
  153. wl_cli/commands/testcommands/coverage_cache_manager.py +183 -0
  154. wl_cli/commands/testcommands/progress_manager.py +79 -0
  155. wl_cli/commands/testcommands/python_env_detector.py +207 -0
  156. wl_cli/commands/testcommands/report_generator.py +101 -0
  157. wl_cli/commands/testcommands/single_test_executor.py +250 -0
  158. wl_cli/commands/testcommands/speed_checker.py +118 -0
  159. wl_cli/commands/testcommands/test_command_builder.py +165 -0
  160. wl_cli/commands/testcommands/test_commands.py +786 -0
  161. wl_cli/commands/testcommands/test_reporter.py +181 -0
  162. wl_cli/commands/testcommands/test_result_handler.py +96 -0
  163. wl_cli/commands/testcommands/test_runner.py +1343 -0
  164. wl_cli/commands/testcommands/test_utils.py +197 -0
  165. wl_cli/commands/testcommands/utils/__init__.py +17 -0
  166. wl_cli/commands/testcommands/utils/coverage_parser.py +98 -0
  167. wl_cli/commands/testcommands/utils/env_info.py +36 -0
  168. wl_cli/commands/testcommands/utils/junit_parser.py +75 -0
  169. wl_cli/commands/testcommands/utils/markdown_utils.py +20 -0
  170. wl_cli/commands/testcommands/utils/project_root.py +61 -0
  171. wl_cli/commands/update/__init__.py +9 -0
  172. wl_cli/commands/update/services/__init__.py +21 -0
  173. wl_cli/commands/update/services/backup_manager.py +207 -0
  174. wl_cli/commands/update/services/component_manager.py +83 -0
  175. wl_cli/commands/update/services/conflict_resolver.py +189 -0
  176. wl_cli/commands/update/services/vendors_updater.py +85 -0
  177. wl_cli/commands/update/services/version_tracker.py +127 -0
  178. wl_cli/commands/update/update_command.py +270 -0
  179. wl_cli/commands/update/utils/__init__.py +3 -0
  180. wl_cli/commands/version/__init__.py +9 -0
  181. wl_cli/commands/version/version_command.py +155 -0
  182. wl_cli/commands/workflow.py +477 -0
  183. wl_cli/env/__init__.py +5 -0
  184. wl_cli/env/cli.py +167 -0
  185. wl_cli/env_status.py +157 -0
  186. wl_cli/envelope.py +91 -0
  187. wl_cli/exceptions.py +85 -0
  188. wl_cli/lib/__init__.py +3 -0
  189. wl_cli/lib/rust_utils.py +35 -0
  190. wl_cli/mcp/__init__.py +6 -0
  191. wl_cli/mcp/capabilities.py +19 -0
  192. wl_cli/mcp/cli.py +22 -0
  193. wl_cli/mcp/gitlab.py +553 -0
  194. wl_cli/mcp/k8s.py +344 -0
  195. wl_cli/mcp/protocol.py +159 -0
  196. wl_cli/platform.py +139 -0
  197. wl_cli/quality/__init__.py +18 -0
  198. wl_cli/utils/__init__.py +7 -0
  199. wl_cli/utils/cache.py +491 -0
  200. wl_cli/utils/cache_ledger.py +355 -0
  201. wl_cli/utils/cache_store.py +546 -0
  202. wl_cli/utils/config/__init__.py +27 -0
  203. wl_cli/utils/config/config_loader.py +163 -0
  204. wl_cli/utils/config/core.py +862 -0
  205. wl_cli/utils/config/defaults.py +142 -0
  206. wl_cli/utils/config/env_exporter.py +86 -0
  207. wl_cli/utils/config/env_parser.py +108 -0
  208. wl_cli/utils/config/validation.py +280 -0
  209. wl_cli/utils/error_handler.py +165 -0
  210. wl_cli/utils/file_copier.py +56 -0
  211. wl_cli/utils/file_operations.py +506 -0
  212. wl_cli/utils/language_utils.py +122 -0
  213. wl_cli/utils/lazy_import.py +240 -0
  214. wl_cli/utils/log_levels.py +35 -0
  215. wl_cli/utils/log_rotators.py +74 -0
  216. wl_cli/utils/logging.py +458 -0
  217. wl_cli/utils/output_context.py +142 -0
  218. wl_cli/utils/performance/__init__.py +1 -0
  219. wl_cli/utils/performance/decorators.py +111 -0
  220. wl_cli/utils/performance/exporter.py +38 -0
  221. wl_cli/utils/performance/models.py +16 -0
  222. wl_cli/utils/performance/monitor.py +161 -0
  223. wl_cli/utils/performance_monitor.py +32 -0
  224. wl_cli/utils/platform_adapter.py +131 -0
  225. wl_cli/utils/pre_commit.py +266 -0
  226. wl_cli/utils/pre_commit_config.py +72 -0
  227. wl_cli/utils/root.py +521 -0
  228. wl_cli/utils/root_fallback.py +256 -0
  229. wl_cli/utils/run_evidence.py +236 -0
  230. wl_cli/utils/structured_logger.py +18 -0
  231. wl_cli/utils/structured_logging/__init__.py +19 -0
  232. wl_cli/utils/structured_logging/config.py +337 -0
  233. wl_cli/utils/structured_logging/core.py +177 -0
  234. wl_cli/utils/structured_logging/env.py +56 -0
  235. wl_cli/utils/structured_logging/filtering.py +75 -0
  236. wl_cli/utils/structured_logging/filters.py +55 -0
  237. wl_cli/utils/structured_logging/formatters.py +251 -0
  238. wl_cli/utils/structured_logging/handlers.py +308 -0
  239. wl_cli/utils/structured_logging/logger.py +354 -0
  240. wl_cli/utils/subprocess.py +71 -0
  241. wl_cli/utils/subprocess_utils.py +260 -0
  242. wl_cli/utils/test_utils/__init__.py +5 -0
  243. wl_cli/utils/test_utils/test_filter.py +36 -0
  244. wl_cli/utils/uv_run.py +79 -0
  245. wl_cli/utils/uv_tool.py +117 -0
  246. wl_cli/utils/uv_tree.py +71 -0
  247. wl_cli/utils/uv_workspace.py +174 -0
  248. wl_cli/utils/version/__init__.py +15 -0
  249. wl_cli/utils/version/pypi_version_checker.py +95 -0
  250. wl_cli/utils/version/version_comparator.py +133 -0
  251. wl_cli/utils/version/version_detectors.py +312 -0
  252. wl_cli/utils/version/version_service.py +131 -0
  253. wl_cli/utils/version/version_updater.py +198 -0
  254. wl_cli/utils/wl_dir_updater.py +1440 -0
  255. wl_cli/utils/workspace_detector/__init__.py +28 -0
  256. wl_cli/utils/workspace_detector/core.py +161 -0
  257. wl_cli/utils/workspace_detector/detection_strategies.py +107 -0
  258. wl_cli/utils/workspace_detector/exceptions.py +5 -0
  259. wl_cli/utils/workspace_detector/types.py +17 -0
  260. wl_cli/utils/workspace_detector/venv_resolver.py +84 -0
  261. wl_cli/vendors/config/.codespellrc +2 -0
  262. wl_cli/vendors/config/dependencies.toml +10 -0
  263. wl_cli/vendors/config/mypy.ini +62 -0
  264. wl_cli/vendors/config/pyproject_defaults.toml +28 -0
  265. wl_cli/vendors/config/template_config.toml +24 -0
  266. wl_cli/vendors/config/tool_configs.toml +76 -0
  267. wl_cli/vendors/git/.gitignore +122 -0
  268. wl_cli/vendors/git/.pre-commit-config.yaml +37 -0
  269. wl_cli/vendors/hooks/applypatch-msg.sample +15 -0
  270. wl_cli/vendors/hooks/commit-msg.sample +24 -0
  271. wl_cli/vendors/hooks/fsmonitor-watchman.sample +174 -0
  272. wl_cli/vendors/hooks/post-update.sample +8 -0
  273. wl_cli/vendors/hooks/pre-applypatch.sample +14 -0
  274. wl_cli/vendors/hooks/pre-commit +45 -0
  275. wl_cli/vendors/hooks/pre-commit.legacy +31 -0
  276. wl_cli/vendors/hooks/pre-commit.sample +49 -0
  277. wl_cli/vendors/hooks/pre-merge-commit.sample +13 -0
  278. wl_cli/vendors/hooks/pre-push.sample +60 -0
  279. wl_cli/vendors/hooks/pre-rebase.sample +169 -0
  280. wl_cli/vendors/hooks/pre-receive.sample +24 -0
  281. wl_cli/vendors/hooks/prepare-commit-msg.sample +42 -0
  282. wl_cli/vendors/hooks/push-to-checkout.sample +78 -0
  283. wl_cli/vendors/hooks/sendemail-validate.sample +77 -0
  284. wl_cli/vendors/hooks/unix/applypatch-msg.sample +15 -0
  285. wl_cli/vendors/hooks/unix/check_lockfile.py +58 -0
  286. wl_cli/vendors/hooks/unix/check_lockfile.sh +36 -0
  287. wl_cli/vendors/hooks/unix/commit-msg.sample +24 -0
  288. wl_cli/vendors/hooks/unix/fsmonitor-watchman.sample +174 -0
  289. wl_cli/vendors/hooks/unix/post-update.sample +8 -0
  290. wl_cli/vendors/hooks/unix/pre-applypatch.sample +14 -0
  291. wl_cli/vendors/hooks/unix/pre-commit +190 -0
  292. wl_cli/vendors/hooks/unix/pre-commit.legacy +31 -0
  293. wl_cli/vendors/hooks/unix/pre-commit.py +81 -0
  294. wl_cli/vendors/hooks/unix/pre-commit.sample +49 -0
  295. wl_cli/vendors/hooks/unix/pre-merge-commit.sample +13 -0
  296. wl_cli/vendors/hooks/unix/pre-push +417 -0
  297. wl_cli/vendors/hooks/unix/pre-push.sample +53 -0
  298. wl_cli/vendors/hooks/unix/pre-rebase.sample +169 -0
  299. wl_cli/vendors/hooks/unix/pre-receive.sample +24 -0
  300. wl_cli/vendors/hooks/unix/prepare-commit-msg.sample +42 -0
  301. wl_cli/vendors/hooks/update.sample +128 -0
  302. wl_cli/vendors/hooks/win/work.bat +63 -0
  303. wl_cli/vendors/project/.gitignore +90 -0
  304. wl_cli/vendors/project/.python-version +1 -0
  305. wl_cli/vendors/project/LICENSE +21 -0
  306. wl_cli/vendors/project/README.md +0 -0
  307. wl_cli/vendors/project/pyproject.toml +27 -0
  308. wl_cli/vendors/project/pyproject_no_workspace.toml +16 -0
  309. wl_cli/vendors/project/pyproject_workspace.toml +14 -0
  310. wl_cli/vendors/readme/README.md +120 -0
  311. wl_cli/vendors/rust/Cargo.toml +14 -0
  312. wl_cli/vendors/rust/lib/__init__.py +3 -0
  313. wl_cli/vendors/rust/lib/rust_utils.py +31 -0
  314. wl_cli/vendors/rust/src/lib.rs +13 -0
  315. wl_cli/vendors/rust/src/main.rs +3 -0
  316. wl_cli/vendors/rust/tests/test_rust_fallback.py +40 -0
  317. wl_cli/vendors/sop_doc/git-dev-sop.md +220 -0
  318. wl_cli/vendors/sop_doc/industrial-standard-sop.md +145 -0
  319. wl_cli/vendors/sop_doc/python-sop.md +342 -0
  320. 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