provide-foundation 0.0.0.dev1__py3-none-any.whl → 0.0.0.dev3__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 (163) hide show
  1. provide/foundation/__init__.py +36 -10
  2. provide/foundation/archive/__init__.py +1 -1
  3. provide/foundation/archive/base.py +15 -14
  4. provide/foundation/archive/bzip2.py +40 -40
  5. provide/foundation/archive/gzip.py +42 -42
  6. provide/foundation/archive/operations.py +93 -96
  7. provide/foundation/archive/tar.py +33 -31
  8. provide/foundation/archive/zip.py +52 -50
  9. provide/foundation/asynctools/__init__.py +20 -0
  10. provide/foundation/asynctools/core.py +126 -0
  11. provide/foundation/cli/__init__.py +2 -2
  12. provide/foundation/cli/commands/deps.py +15 -9
  13. provide/foundation/cli/commands/logs/__init__.py +3 -3
  14. provide/foundation/cli/commands/logs/generate.py +2 -2
  15. provide/foundation/cli/commands/logs/query.py +4 -4
  16. provide/foundation/cli/commands/logs/send.py +3 -3
  17. provide/foundation/cli/commands/logs/tail.py +3 -3
  18. provide/foundation/cli/decorators.py +11 -11
  19. provide/foundation/cli/main.py +1 -1
  20. provide/foundation/cli/testing.py +2 -40
  21. provide/foundation/cli/utils.py +21 -18
  22. provide/foundation/config/__init__.py +35 -2
  23. provide/foundation/config/base.py +2 -2
  24. provide/foundation/config/converters.py +477 -0
  25. provide/foundation/config/defaults.py +67 -0
  26. provide/foundation/config/env.py +6 -20
  27. provide/foundation/config/loader.py +10 -4
  28. provide/foundation/config/sync.py +8 -6
  29. provide/foundation/config/types.py +5 -5
  30. provide/foundation/config/validators.py +4 -4
  31. provide/foundation/console/input.py +5 -5
  32. provide/foundation/console/output.py +36 -14
  33. provide/foundation/context/__init__.py +8 -4
  34. provide/foundation/context/core.py +88 -110
  35. provide/foundation/crypto/certificates/__init__.py +9 -5
  36. provide/foundation/crypto/certificates/base.py +2 -2
  37. provide/foundation/crypto/certificates/certificate.py +48 -19
  38. provide/foundation/crypto/certificates/factory.py +26 -18
  39. provide/foundation/crypto/certificates/generator.py +24 -23
  40. provide/foundation/crypto/certificates/loader.py +24 -16
  41. provide/foundation/crypto/certificates/operations.py +17 -10
  42. provide/foundation/crypto/certificates/trust.py +21 -21
  43. provide/foundation/env/__init__.py +28 -0
  44. provide/foundation/env/core.py +218 -0
  45. provide/foundation/errors/__init__.py +3 -3
  46. provide/foundation/errors/decorators.py +0 -234
  47. provide/foundation/errors/types.py +0 -98
  48. provide/foundation/eventsets/display.py +13 -14
  49. provide/foundation/eventsets/registry.py +61 -31
  50. provide/foundation/eventsets/resolver.py +50 -46
  51. provide/foundation/eventsets/sets/das.py +8 -8
  52. provide/foundation/eventsets/sets/database.py +14 -14
  53. provide/foundation/eventsets/sets/http.py +21 -21
  54. provide/foundation/eventsets/sets/llm.py +16 -16
  55. provide/foundation/eventsets/sets/task_queue.py +13 -13
  56. provide/foundation/eventsets/types.py +7 -7
  57. provide/foundation/file/directory.py +14 -23
  58. provide/foundation/file/lock.py +4 -3
  59. provide/foundation/hub/components.py +75 -389
  60. provide/foundation/hub/config.py +157 -0
  61. provide/foundation/hub/discovery.py +63 -0
  62. provide/foundation/hub/handlers.py +89 -0
  63. provide/foundation/hub/lifecycle.py +195 -0
  64. provide/foundation/hub/manager.py +7 -4
  65. provide/foundation/hub/processors.py +49 -0
  66. provide/foundation/integrations/__init__.py +11 -0
  67. provide/foundation/{observability → integrations}/openobserve/__init__.py +10 -7
  68. provide/foundation/{observability → integrations}/openobserve/auth.py +1 -1
  69. provide/foundation/{observability → integrations}/openobserve/client.py +14 -14
  70. provide/foundation/{observability → integrations}/openobserve/commands.py +12 -12
  71. provide/foundation/integrations/openobserve/config.py +37 -0
  72. provide/foundation/{observability → integrations}/openobserve/formatters.py +1 -1
  73. provide/foundation/{observability → integrations}/openobserve/otlp.py +2 -2
  74. provide/foundation/{observability → integrations}/openobserve/search.py +2 -3
  75. provide/foundation/{observability → integrations}/openobserve/streaming.py +5 -5
  76. provide/foundation/logger/__init__.py +0 -1
  77. provide/foundation/logger/config/base.py +1 -1
  78. provide/foundation/logger/config/logging.py +69 -299
  79. provide/foundation/logger/config/telemetry.py +39 -121
  80. provide/foundation/logger/factories.py +2 -2
  81. provide/foundation/logger/processors/main.py +12 -10
  82. provide/foundation/logger/ratelimit/limiters.py +4 -4
  83. provide/foundation/logger/ratelimit/processor.py +1 -1
  84. provide/foundation/logger/setup/coordinator.py +39 -25
  85. provide/foundation/logger/setup/processors.py +3 -3
  86. provide/foundation/logger/setup/testing.py +14 -0
  87. provide/foundation/logger/trace.py +5 -5
  88. provide/foundation/metrics/__init__.py +1 -1
  89. provide/foundation/metrics/otel.py +3 -1
  90. provide/foundation/observability/__init__.py +3 -3
  91. provide/foundation/process/__init__.py +9 -0
  92. provide/foundation/process/exit.py +48 -0
  93. provide/foundation/process/lifecycle.py +69 -46
  94. provide/foundation/resilience/__init__.py +36 -0
  95. provide/foundation/resilience/circuit.py +166 -0
  96. provide/foundation/resilience/decorators.py +236 -0
  97. provide/foundation/resilience/fallback.py +208 -0
  98. provide/foundation/resilience/retry.py +327 -0
  99. provide/foundation/serialization/__init__.py +16 -0
  100. provide/foundation/serialization/core.py +70 -0
  101. provide/foundation/streams/config.py +78 -0
  102. provide/foundation/streams/console.py +4 -5
  103. provide/foundation/streams/core.py +5 -2
  104. provide/foundation/streams/file.py +12 -2
  105. provide/foundation/testing/__init__.py +29 -9
  106. provide/foundation/testing/archive/__init__.py +7 -7
  107. provide/foundation/testing/archive/fixtures.py +58 -54
  108. provide/foundation/testing/cli.py +30 -20
  109. provide/foundation/testing/common/__init__.py +13 -15
  110. provide/foundation/testing/common/fixtures.py +27 -57
  111. provide/foundation/testing/file/__init__.py +15 -15
  112. provide/foundation/testing/file/content_fixtures.py +289 -0
  113. provide/foundation/testing/file/directory_fixtures.py +107 -0
  114. provide/foundation/testing/file/fixtures.py +42 -516
  115. provide/foundation/testing/file/special_fixtures.py +145 -0
  116. provide/foundation/testing/logger.py +89 -8
  117. provide/foundation/testing/mocking/__init__.py +21 -21
  118. provide/foundation/testing/mocking/fixtures.py +80 -67
  119. provide/foundation/testing/process/__init__.py +23 -23
  120. provide/foundation/testing/process/async_fixtures.py +414 -0
  121. provide/foundation/testing/process/fixtures.py +48 -571
  122. provide/foundation/testing/process/subprocess_fixtures.py +210 -0
  123. provide/foundation/testing/threading/__init__.py +17 -17
  124. provide/foundation/testing/threading/basic_fixtures.py +105 -0
  125. provide/foundation/testing/threading/data_fixtures.py +101 -0
  126. provide/foundation/testing/threading/execution_fixtures.py +278 -0
  127. provide/foundation/testing/threading/fixtures.py +32 -502
  128. provide/foundation/testing/threading/sync_fixtures.py +100 -0
  129. provide/foundation/testing/time/__init__.py +11 -11
  130. provide/foundation/testing/time/fixtures.py +95 -83
  131. provide/foundation/testing/transport/__init__.py +9 -9
  132. provide/foundation/testing/transport/fixtures.py +54 -54
  133. provide/foundation/time/__init__.py +18 -0
  134. provide/foundation/time/core.py +63 -0
  135. provide/foundation/tools/__init__.py +2 -2
  136. provide/foundation/tools/base.py +68 -67
  137. provide/foundation/tools/cache.py +69 -74
  138. provide/foundation/tools/downloader.py +68 -62
  139. provide/foundation/tools/installer.py +51 -57
  140. provide/foundation/tools/registry.py +38 -45
  141. provide/foundation/tools/resolver.py +70 -68
  142. provide/foundation/tools/verifier.py +39 -50
  143. provide/foundation/tracer/spans.py +2 -14
  144. provide/foundation/transport/__init__.py +26 -33
  145. provide/foundation/transport/base.py +32 -30
  146. provide/foundation/transport/client.py +44 -49
  147. provide/foundation/transport/config.py +36 -107
  148. provide/foundation/transport/errors.py +13 -27
  149. provide/foundation/transport/http.py +69 -55
  150. provide/foundation/transport/middleware.py +113 -114
  151. provide/foundation/transport/registry.py +29 -27
  152. provide/foundation/transport/types.py +6 -6
  153. provide/foundation/utils/deps.py +17 -14
  154. provide/foundation/utils/parsing.py +49 -4
  155. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/METADATA +2 -2
  156. provide_foundation-0.0.0.dev3.dist-info/RECORD +233 -0
  157. provide_foundation-0.0.0.dev1.dist-info/RECORD +0 -200
  158. /provide/foundation/{observability → integrations}/openobserve/exceptions.py +0 -0
  159. /provide/foundation/{observability → integrations}/openobserve/models.py +0 -0
  160. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/WHEEL +0 -0
  161. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/entry_points.txt +0 -0
  162. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/licenses/LICENSE +0 -0
  163. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/top_level.txt +0 -0
@@ -5,11 +5,10 @@ Handles extraction and installation of tools from different
5
5
  archive formats (zip, tar, gz, etc.) and binary files.
6
6
  """
7
7
 
8
+ from pathlib import Path
8
9
  import shutil
9
10
  import tarfile
10
- import tempfile
11
11
  import zipfile
12
- from pathlib import Path
13
12
 
14
13
  from provide.foundation.errors import FoundationError
15
14
  from provide.foundation.logger import get_logger
@@ -20,43 +19,43 @@ log = get_logger(__name__)
20
19
 
21
20
  class InstallError(FoundationError):
22
21
  """Raised when installation fails."""
23
-
22
+
24
23
  pass
25
24
 
26
25
 
27
26
  class ToolInstaller:
28
27
  """
29
28
  Handle tool installation from various artifact formats.
30
-
29
+
31
30
  Supports:
32
31
  - ZIP archives
33
32
  - TAR archives (with compression)
34
33
  - Single binary files
35
34
  - Platform-specific installation patterns
36
35
  """
37
-
36
+
38
37
  def install(self, artifact: Path, metadata: ToolMetadata) -> Path:
39
38
  """
40
39
  Install tool from artifact.
41
-
40
+
42
41
  Args:
43
42
  artifact: Path to downloaded artifact.
44
43
  metadata: Tool metadata with installation info.
45
-
44
+
46
45
  Returns:
47
46
  Path to installed tool directory.
48
-
47
+
49
48
  Raises:
50
49
  InstallError: If installation fails.
51
50
  """
52
51
  if not artifact.exists():
53
52
  raise InstallError(f"Artifact not found: {artifact}")
54
-
53
+
55
54
  # Determine install directory
56
55
  install_dir = self.get_install_dir(metadata)
57
-
56
+
58
57
  log.info(f"Installing {metadata.name} {metadata.version} to {install_dir}")
59
-
58
+
60
59
  # Extract based on file type
61
60
  suffix = artifact.suffix.lower()
62
61
  if suffix == ".zip":
@@ -67,65 +66,65 @@ class ToolInstaller:
67
66
  self.install_binary(artifact, install_dir, metadata)
68
67
  else:
69
68
  raise InstallError(f"Unknown artifact type: {suffix}")
70
-
69
+
71
70
  # Set permissions
72
71
  self.set_permissions(install_dir, metadata)
73
-
72
+
74
73
  # Create symlinks if needed
75
74
  self.create_symlinks(install_dir, metadata)
76
-
75
+
77
76
  log.info(f"Successfully installed {metadata.name} to {install_dir}")
78
77
  return install_dir
79
-
78
+
80
79
  def get_install_dir(self, metadata: ToolMetadata) -> Path:
81
80
  """
82
81
  Get installation directory for tool.
83
-
82
+
84
83
  Args:
85
84
  metadata: Tool metadata.
86
-
85
+
87
86
  Returns:
88
87
  Installation directory path.
89
88
  """
90
89
  if metadata.install_path:
91
90
  return metadata.install_path
92
-
91
+
93
92
  # Default to ~/.wrknv/tools/<name>/<version>
94
93
  base = Path.home() / ".wrknv" / "tools"
95
94
  return base / metadata.name / metadata.version
96
-
95
+
97
96
  def extract_zip(self, archive: Path, dest: Path) -> None:
98
97
  """
99
98
  Extract ZIP archive.
100
-
99
+
101
100
  Args:
102
101
  archive: Path to ZIP file.
103
102
  dest: Destination directory.
104
103
  """
105
104
  log.debug(f"Extracting ZIP {archive} to {dest}")
106
-
105
+
107
106
  dest.mkdir(parents=True, exist_ok=True)
108
-
107
+
109
108
  with zipfile.ZipFile(archive, "r") as zf:
110
109
  # Check for unsafe paths
111
110
  for member in zf.namelist():
112
111
  if member.startswith("/") or ".." in member:
113
112
  raise InstallError(f"Unsafe path in archive: {member}")
114
-
113
+
115
114
  zf.extractall(dest)
116
-
115
+
117
116
  def extract_tar(self, archive: Path, dest: Path) -> None:
118
117
  """
119
118
  Extract tar archive (with optional compression).
120
-
119
+
121
120
  Args:
122
121
  archive: Path to tar file.
123
122
  dest: Destination directory.
124
123
  """
125
124
  log.debug(f"Extracting tar {archive} to {dest}")
126
-
125
+
127
126
  dest.mkdir(parents=True, exist_ok=True)
128
-
127
+
129
128
  # Determine mode based on extension
130
129
  mode = "r"
131
130
  if archive.suffix in [".gz", ".tgz"]:
@@ -134,22 +133,22 @@ class ToolInstaller:
134
133
  mode = "r:bz2"
135
134
  elif archive.suffix == ".xz":
136
135
  mode = "r:xz"
137
-
136
+
138
137
  with tarfile.open(archive, mode) as tf:
139
138
  # Check for unsafe paths
140
139
  for member in tf.getmembers():
141
140
  if member.name.startswith("/") or ".." in member.name:
142
141
  raise InstallError(f"Unsafe path in archive: {member.name}")
143
-
142
+
144
143
  tf.extractall(dest)
145
-
144
+
146
145
  def is_binary(self, file_path: Path) -> bool:
147
146
  """
148
147
  Check if file is a binary executable.
149
-
148
+
150
149
  Args:
151
150
  file_path: Path to check.
152
-
151
+
153
152
  Returns:
154
153
  True if file appears to be binary.
155
154
  """
@@ -170,85 +169,80 @@ class ToolInstaller:
170
169
  return True
171
170
  except Exception:
172
171
  pass
173
-
172
+
174
173
  return False
175
-
176
- def install_binary(
177
- self,
178
- binary: Path,
179
- dest: Path,
180
- metadata: ToolMetadata
181
- ) -> None:
174
+
175
+ def install_binary(self, binary: Path, dest: Path, metadata: ToolMetadata) -> None:
182
176
  """
183
177
  Install single binary file.
184
-
178
+
185
179
  Args:
186
180
  binary: Path to binary file.
187
181
  dest: Destination directory.
188
182
  metadata: Tool metadata.
189
183
  """
190
184
  log.debug(f"Installing binary {binary} to {dest}")
191
-
185
+
192
186
  dest.mkdir(parents=True, exist_ok=True)
193
187
  bin_dir = dest / "bin"
194
188
  bin_dir.mkdir(exist_ok=True)
195
-
189
+
196
190
  # Determine target name
197
191
  target_name = metadata.executable_name or binary.name
198
192
  target = bin_dir / target_name
199
-
193
+
200
194
  # Copy binary
201
195
  shutil.copy2(binary, target)
202
-
196
+
203
197
  # Make executable
204
198
  target.chmod(0o755)
205
-
199
+
206
200
  def set_permissions(self, install_dir: Path, metadata: ToolMetadata) -> None:
207
201
  """
208
202
  Set appropriate permissions on installed files.
209
-
203
+
210
204
  Args:
211
205
  install_dir: Installation directory.
212
206
  metadata: Tool metadata.
213
207
  """
214
208
  import platform
215
-
209
+
216
210
  if platform.system() == "Windows":
217
211
  return # Windows handles permissions differently
218
-
212
+
219
213
  # Find executables and make them executable
220
214
  bin_dir = install_dir / "bin"
221
215
  if bin_dir.exists():
222
216
  for file in bin_dir.iterdir():
223
217
  if file.is_file():
224
218
  file.chmod(0o755)
225
-
219
+
226
220
  # Check for executable name in root
227
221
  if metadata.executable_name:
228
222
  exe_path = install_dir / metadata.executable_name
229
223
  if exe_path.exists():
230
224
  exe_path.chmod(0o755)
231
-
225
+
232
226
  def create_symlinks(self, install_dir: Path, metadata: ToolMetadata) -> None:
233
227
  """
234
228
  Create symlinks for easier access.
235
-
229
+
236
230
  Args:
237
231
  install_dir: Installation directory.
238
232
  metadata: Tool metadata.
239
233
  """
240
234
  import platform
241
-
235
+
242
236
  if platform.system() == "Windows":
243
237
  return # Windows doesn't support symlinks easily
244
-
238
+
245
239
  # Create version-less symlink
246
240
  if metadata.name and metadata.version:
247
241
  parent = install_dir.parent
248
242
  latest_link = parent / "latest"
249
-
243
+
250
244
  if latest_link.exists() or latest_link.is_symlink():
251
245
  latest_link.unlink()
252
-
246
+
253
247
  latest_link.symlink_to(install_dir)
254
- log.debug(f"Created symlink {latest_link} -> {install_dir}")
248
+ log.debug(f"Created symlink {latest_link} -> {install_dir}")
@@ -19,32 +19,32 @@ log = get_logger(__name__)
19
19
  class ToolRegistry:
20
20
  """
21
21
  Wrapper around the hub registry for tool management.
22
-
22
+
23
23
  Uses the main hub registry with dimension="tool_manager"
24
24
  to avoid namespace pollution while leveraging existing
25
25
  registry infrastructure.
26
26
  """
27
-
27
+
28
28
  DIMENSION = "tool_manager"
29
-
29
+
30
30
  def __init__(self):
31
31
  """Initialize the tool registry."""
32
32
  self.hub = get_hub()
33
33
  self._discover_tools()
34
-
34
+
35
35
  def _discover_tools(self) -> None:
36
36
  """
37
37
  Auto-discover tool managers via entry points.
38
-
38
+
39
39
  Looks for entry points in the "wrknv.tools" group
40
40
  and automatically registers them.
41
41
  """
42
42
  try:
43
43
  # Get entry points for tool managers
44
- if hasattr(importlib.metadata, 'entry_points'):
44
+ if hasattr(importlib.metadata, "entry_points"):
45
45
  # Python 3.10+
46
46
  eps = importlib.metadata.entry_points()
47
- if hasattr(eps, 'select'):
47
+ if hasattr(eps, "select"):
48
48
  # Python 3.10+ with select method
49
49
  group_eps = eps.select(group="wrknv.tools")
50
50
  else:
@@ -54,7 +54,7 @@ class ToolRegistry:
54
54
  # Python 3.8-3.9
55
55
  eps = importlib.metadata.entry_points()
56
56
  group_eps = eps.get("wrknv.tools", [])
57
-
57
+
58
58
  for ep in group_eps:
59
59
  try:
60
60
  manager_class = ep.load()
@@ -64,16 +64,16 @@ class ToolRegistry:
64
64
  log.warning(f"Failed to load tool manager {ep.name}: {e}")
65
65
  except Exception as e:
66
66
  log.debug(f"Entry point discovery not available: {e}")
67
-
67
+
68
68
  def register_tool_manager(
69
69
  self,
70
70
  name: str,
71
71
  manager_class: type[BaseToolManager],
72
- aliases: list[str] | None = None
72
+ aliases: list[str] | None = None,
73
73
  ) -> None:
74
74
  """
75
75
  Register a tool manager with the hub.
76
-
76
+
77
77
  Args:
78
78
  name: Tool name (e.g., "terraform").
79
79
  manager_class: Tool manager class.
@@ -85,7 +85,7 @@ class ToolRegistry:
85
85
  "executable": manager_class.executable_name,
86
86
  "platforms": manager_class.supported_platforms,
87
87
  }
88
-
88
+
89
89
  # Register with hub
90
90
  self.hub.registry.register(
91
91
  name=name,
@@ -93,35 +93,33 @@ class ToolRegistry:
93
93
  dimension=self.DIMENSION,
94
94
  metadata=metadata,
95
95
  aliases=aliases,
96
- replace=True # Allow re-registration for updates
96
+ replace=True, # Allow re-registration for updates
97
97
  )
98
-
98
+
99
99
  log.info(f"Registered tool manager: {name}")
100
-
100
+
101
101
  def get_tool_manager_class(self, name: str) -> type[BaseToolManager] | None:
102
102
  """
103
103
  Get a tool manager class by name.
104
-
104
+
105
105
  Args:
106
106
  name: Tool name or alias.
107
-
107
+
108
108
  Returns:
109
109
  Tool manager class, or None if not found.
110
110
  """
111
111
  return self.hub.registry.get(name, dimension=self.DIMENSION)
112
-
112
+
113
113
  def create_tool_manager(
114
- self,
115
- name: str,
116
- config: BaseConfig
114
+ self, name: str, config: BaseConfig
117
115
  ) -> BaseToolManager | None:
118
116
  """
119
117
  Create a tool manager instance.
120
-
118
+
121
119
  Args:
122
120
  name: Tool name or alias.
123
121
  config: Configuration object.
124
-
122
+
125
123
  Returns:
126
124
  Tool manager instance, or None if not found.
127
125
  """
@@ -129,42 +127,42 @@ class ToolRegistry:
129
127
  if manager_class:
130
128
  return manager_class(config)
131
129
  return None
132
-
130
+
133
131
  def list_tools(self) -> list[tuple[str, dict[str, Any]]]:
134
132
  """
135
133
  List all registered tools.
136
-
134
+
137
135
  Returns:
138
136
  List of (name, metadata) tuples.
139
137
  """
140
138
  tools = []
141
139
  for name, entry in self.hub.registry.list_dimension(self.DIMENSION):
142
- metadata = entry.metadata if hasattr(entry, 'metadata') else {}
140
+ metadata = entry.metadata if hasattr(entry, "metadata") else {}
143
141
  tools.append((name, metadata))
144
142
  return tools
145
-
143
+
146
144
  def get_tool_info(self, name: str) -> dict[str, Any] | None:
147
145
  """
148
146
  Get information about a specific tool.
149
-
147
+
150
148
  Args:
151
149
  name: Tool name or alias.
152
-
150
+
153
151
  Returns:
154
152
  Tool metadata dictionary, or None if not found.
155
153
  """
156
154
  entry = self.hub.registry.get_entry(name, dimension=self.DIMENSION)
157
- if entry and hasattr(entry, 'metadata'):
155
+ if entry and hasattr(entry, "metadata"):
158
156
  return entry.metadata
159
157
  return None
160
-
158
+
161
159
  def is_tool_registered(self, name: str) -> bool:
162
160
  """
163
161
  Check if a tool is registered.
164
-
162
+
165
163
  Args:
166
164
  name: Tool name or alias.
167
-
165
+
168
166
  Returns:
169
167
  True if registered, False otherwise.
170
168
  """
@@ -178,7 +176,7 @@ _tool_registry: ToolRegistry | None = None
178
176
  def get_tool_registry() -> ToolRegistry:
179
177
  """
180
178
  Get the global tool registry instance.
181
-
179
+
182
180
  Returns:
183
181
  Tool registry instance.
184
182
  """
@@ -189,13 +187,11 @@ def get_tool_registry() -> ToolRegistry:
189
187
 
190
188
 
191
189
  def register_tool_manager(
192
- name: str,
193
- manager_class: type[BaseToolManager],
194
- aliases: list[str] | None = None
190
+ name: str, manager_class: type[BaseToolManager], aliases: list[str] | None = None
195
191
  ) -> None:
196
192
  """
197
193
  Register a tool manager with the global registry.
198
-
194
+
199
195
  Args:
200
196
  name: Tool name.
201
197
  manager_class: Tool manager class.
@@ -205,19 +201,16 @@ def register_tool_manager(
205
201
  registry.register_tool_manager(name, manager_class, aliases)
206
202
 
207
203
 
208
- def get_tool_manager(
209
- name: str,
210
- config: BaseConfig
211
- ) -> BaseToolManager | None:
204
+ def get_tool_manager(name: str, config: BaseConfig) -> BaseToolManager | None:
212
205
  """
213
206
  Get a tool manager instance from the global registry.
214
-
207
+
215
208
  Args:
216
209
  name: Tool name or alias.
217
210
  config: Configuration object.
218
-
211
+
219
212
  Returns:
220
213
  Tool manager instance, or None if not found.
221
214
  """
222
215
  registry = get_tool_registry()
223
- return registry.create_tool_manager(name, config)
216
+ return registry.create_tool_manager(name, config)