solidworks-mcp-python 1.5.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 (115) hide show
  1. solidworks_mcp/__init__.py +57 -0
  2. solidworks_mcp/adapters/__init__.py +40 -0
  3. solidworks_mcp/adapters/base.py +1882 -0
  4. solidworks_mcp/adapters/circuit_breaker.py +2052 -0
  5. solidworks_mcp/adapters/com_executor.py +252 -0
  6. solidworks_mcp/adapters/complexity_analyzer.py +272 -0
  7. solidworks_mcp/adapters/connection_pool.py +1884 -0
  8. solidworks_mcp/adapters/factory.py +366 -0
  9. solidworks_mcp/adapters/intelligent_router.py +218 -0
  10. solidworks_mcp/adapters/mock_adapter.py +4016 -0
  11. solidworks_mcp/adapters/pywin32_adapter.py +2842 -0
  12. solidworks_mcp/adapters/solidworks/__init__.py +17 -0
  13. solidworks_mcp/adapters/solidworks/bitmap.py +180 -0
  14. solidworks_mcp/adapters/solidworks/com_utils.py +56 -0
  15. solidworks_mcp/adapters/solidworks/dimension_layout.py +753 -0
  16. solidworks_mcp/adapters/solidworks/documentation.py +1476 -0
  17. solidworks_mcp/adapters/solidworks/drawing_standard.py +1993 -0
  18. solidworks_mcp/adapters/solidworks/face_selection.py +392 -0
  19. solidworks_mcp/adapters/solidworks/features.py +3362 -0
  20. solidworks_mcp/adapters/solidworks/io.py +3649 -0
  21. solidworks_mcp/adapters/solidworks/rebuild_diagnostics.py +269 -0
  22. solidworks_mcp/adapters/solidworks/rebuild_inspector.py +146 -0
  23. solidworks_mcp/adapters/solidworks/selection.py +308 -0
  24. solidworks_mcp/adapters/solidworks/sketch.py +2545 -0
  25. solidworks_mcp/adapters/sw_feature_errors.py +66 -0
  26. solidworks_mcp/adapters/sw_type_info.py +317 -0
  27. solidworks_mcp/adapters/vba_adapter.py +318 -0
  28. solidworks_mcp/adapters/vba_macro_executor.py +215 -0
  29. solidworks_mcp/agents/__init__.py +68 -0
  30. solidworks_mcp/agents/design_knowledge/assembly_patterns.md +127 -0
  31. solidworks_mcp/agents/design_knowledge/hinges.md +118 -0
  32. solidworks_mcp/agents/design_knowledge/snap_fits.md +93 -0
  33. solidworks_mcp/agents/design_knowledge/solidworks_basics.md +3 -0
  34. solidworks_mcp/agents/design_knowledge/tolerancing.md +128 -0
  35. solidworks_mcp/agents/harness.py +216 -0
  36. solidworks_mcp/agents/history_db.py +1508 -0
  37. solidworks_mcp/agents/retrieval_index.py +164 -0
  38. solidworks_mcp/agents/schemas.py +165 -0
  39. solidworks_mcp/agents/smoke_test.py +285 -0
  40. solidworks_mcp/agents/soc_exporter.py +650 -0
  41. solidworks_mcp/agents/soc_pickup.py +332 -0
  42. solidworks_mcp/agents/soc_rewind.py +221 -0
  43. solidworks_mcp/agents/vector_rag.py +665 -0
  44. solidworks_mcp/cache/__init__.py +5 -0
  45. solidworks_mcp/cache/response_cache.py +164 -0
  46. solidworks_mcp/config.py +729 -0
  47. solidworks_mcp/exceptions.py +37 -0
  48. solidworks_mcp/security/__init__.py +68 -0
  49. solidworks_mcp/security/auth.py +128 -0
  50. solidworks_mcp/security/cors.py +27 -0
  51. solidworks_mcp/security/rate_limiting.py +90 -0
  52. solidworks_mcp/security/runtime.py +155 -0
  53. solidworks_mcp/server.py +777 -0
  54. solidworks_mcp/server_cli_fixed.py +120 -0
  55. solidworks_mcp/setup/__init__.py +1 -0
  56. solidworks_mcp/setup/cli.py +399 -0
  57. solidworks_mcp/setup/clients.py +157 -0
  58. solidworks_mcp/setup/config_file.py +230 -0
  59. solidworks_mcp/setup/handshake.py +202 -0
  60. solidworks_mcp/setup/launcher.py +102 -0
  61. solidworks_mcp/setup/legacy.py +100 -0
  62. solidworks_mcp/setup/registration.py +193 -0
  63. solidworks_mcp/setup/solidworks.py +49 -0
  64. solidworks_mcp/tools/__init__.py +64 -0
  65. solidworks_mcp/tools/analysis.py +723 -0
  66. solidworks_mcp/tools/automation.py +578 -0
  67. solidworks_mcp/tools/docs_discovery.py +1476 -0
  68. solidworks_mcp/tools/drawing.py +1015 -0
  69. solidworks_mcp/tools/drawing_analysis.py +456 -0
  70. solidworks_mcp/tools/drawing_automation.py +627 -0
  71. solidworks_mcp/tools/engineering_data.py +466 -0
  72. solidworks_mcp/tools/error_classifier.py +232 -0
  73. solidworks_mcp/tools/export.py +833 -0
  74. solidworks_mcp/tools/file_facts.py +40 -0
  75. solidworks_mcp/tools/file_management.py +1473 -0
  76. solidworks_mcp/tools/input_compat.py +17 -0
  77. solidworks_mcp/tools/macro_recording.py +464 -0
  78. solidworks_mcp/tools/modeling.py +2360 -0
  79. solidworks_mcp/tools/sketching.py +1422 -0
  80. solidworks_mcp/tools/template_management.py +367 -0
  81. solidworks_mcp/tools/tool_boundary.py +280 -0
  82. solidworks_mcp/tools/vba_generation.py +1145 -0
  83. solidworks_mcp/ui/__init__.py +9 -0
  84. solidworks_mcp/ui/local_llm.py +725 -0
  85. solidworks_mcp/ui/routers/__init__.py +10 -0
  86. solidworks_mcp/ui/routers/checkpoint.py +24 -0
  87. solidworks_mcp/ui/routers/docs.py +47 -0
  88. solidworks_mcp/ui/routers/llm.py +83 -0
  89. solidworks_mcp/ui/routers/local_model.py +69 -0
  90. solidworks_mcp/ui/routers/model.py +75 -0
  91. solidworks_mcp/ui/routers/preview.py +38 -0
  92. solidworks_mcp/ui/routers/session.py +161 -0
  93. solidworks_mcp/ui/routers/viewer.py +154 -0
  94. solidworks_mcp/ui/schemas.py +502 -0
  95. solidworks_mcp/ui/server.py +298 -0
  96. solidworks_mcp/ui/service.py +481 -0
  97. solidworks_mcp/ui/services/__init__.py +136 -0
  98. solidworks_mcp/ui/services/_utils.py +958 -0
  99. solidworks_mcp/ui/services/checkpoint_service.py +1110 -0
  100. solidworks_mcp/ui/services/docs_service.py +282 -0
  101. solidworks_mcp/ui/services/llm_service.py +956 -0
  102. solidworks_mcp/ui/services/model_service.py +459 -0
  103. solidworks_mcp/ui/services/parameter_repair_service.py +314 -0
  104. solidworks_mcp/ui/services/preview_service.py +489 -0
  105. solidworks_mcp/ui/services/session_service.py +1389 -0
  106. solidworks_mcp/utils/__init__.py +9 -0
  107. solidworks_mcp/utils/feature_tree_classifier.py +342 -0
  108. solidworks_mcp/utils/logging.py +76 -0
  109. solidworks_mcp/utils/validation.py +77 -0
  110. solidworks_mcp/version.py +8 -0
  111. solidworks_mcp_python-1.5.0.dist-info/METADATA +410 -0
  112. solidworks_mcp_python-1.5.0.dist-info/RECORD +115 -0
  113. solidworks_mcp_python-1.5.0.dist-info/WHEEL +4 -0
  114. solidworks_mcp_python-1.5.0.dist-info/entry_points.txt +3 -0
  115. solidworks_mcp_python-1.5.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1884 @@
1
+ """Connection pool adapter for managing multiple SolidWorks connections.
2
+
3
+ Provides connection pooling capabilities to allow parallel SolidWorks operations when
4
+ multiple instances are available.
5
+ """
6
+
7
+ import asyncio
8
+ import time
9
+ from collections.abc import Awaitable, Callable
10
+ from datetime import datetime
11
+ from typing import Any, TypeVar, cast
12
+
13
+ from loguru import logger
14
+
15
+ from .base import (
16
+ AdapterHealth,
17
+ AdapterResult,
18
+ AdapterResultStatus,
19
+ ExtrusionParameters,
20
+ LoftParameters,
21
+ MassProperties,
22
+ RevolveParameters,
23
+ SolidWorksAdapter,
24
+ SolidWorksFeature,
25
+ SolidWorksModel,
26
+ SweepParameters,
27
+ )
28
+
29
+ T = TypeVar("T")
30
+
31
+
32
+ class ConnectionPoolAdapter(SolidWorksAdapter):
33
+ """Connection pool wrapper for SolidWorks adapters.
34
+
35
+ Args:
36
+ adapter_factory (Callable[[], SolidWorksAdapter] | None): Factory callable used to
37
+ create adapter instances.
38
+ Defaults to None.
39
+ pool_size (int): Number of adapters to maintain in the pool. Defaults to 3.
40
+ max_retries (int): Maximum number of retry attempts. Defaults to 3.
41
+ create_connection (Callable[[], SolidWorksAdapter] | None): Factory callable used to
42
+ create a connection.
43
+ Defaults to None.
44
+ max_size (int | None): Maximum number of items allowed in the pool. Defaults to
45
+ None.
46
+ timeout (float | None): Maximum time to wait in seconds. Defaults to None.
47
+ config (dict[str, object] | None): Configuration values for the operation. Defaults
48
+ to None.
49
+
50
+ Attributes:
51
+ _lock (Any): The lock value.
52
+ adapter_factory (Any): The adapter factory value.
53
+ max_retries (Any): The max retries value.
54
+ pool_initialized (Any): The pool initialized value.
55
+ pool_size (Any): The pool size value.
56
+ timeout (Any): The timeout value.
57
+ """
58
+
59
+ def __init__(
60
+ self,
61
+ adapter_factory: Callable[[], SolidWorksAdapter] | None = None,
62
+ pool_size: int = 3,
63
+ max_retries: int = 3,
64
+ create_connection: Callable[[], SolidWorksAdapter] | None = None,
65
+ max_size: int | None = None,
66
+ timeout: float | None = None,
67
+ config: dict[str, object] | None = None,
68
+ ) -> None:
69
+ """Initialize the connection pool adapter.
70
+
71
+ Args:
72
+ adapter_factory (Callable[[], SolidWorksAdapter] | None): Factory callable used to
73
+ create adapter instances.
74
+ Defaults to None.
75
+ pool_size (int): Number of adapters to maintain in the pool. Defaults to 3.
76
+ max_retries (int): Maximum number of retry attempts. Defaults to 3.
77
+ create_connection (Callable[[], SolidWorksAdapter] | None): Factory callable used to
78
+ create a connection.
79
+ Defaults to None.
80
+ max_size (int | None): Maximum number of items allowed in the pool. Defaults to
81
+ None.
82
+ timeout (float | None): Maximum time to wait in seconds. Defaults to None.
83
+ config (dict[str, object] | None): Configuration values for the operation. Defaults
84
+ to None.
85
+
86
+ Returns:
87
+ None: None.
88
+ """
89
+ if adapter_factory is None and create_connection is not None:
90
+ adapter_factory = create_connection
91
+ if max_size is not None:
92
+ pool_size = max_size
93
+ if adapter_factory is None:
94
+ from .mock_adapter import MockSolidWorksAdapter
95
+
96
+ def adapter_factory() -> MockSolidWorksAdapter:
97
+ """Provide adapter factory support for the connection pool adapter.
98
+
99
+ Returns:
100
+ MockSolidWorksAdapter: The result produced by the operation.
101
+ """
102
+
103
+ return MockSolidWorksAdapter(config or {})
104
+
105
+ super().__init__(config)
106
+ self.adapter_factory = adapter_factory
107
+ self.pool_size = pool_size
108
+ self.max_retries = max_retries
109
+
110
+ self.pool: list[SolidWorksAdapter] = []
111
+ self.available_adapters: asyncio.Queue[SolidWorksAdapter] = asyncio.Queue()
112
+ self.pool_initialized = False
113
+ self._lock = asyncio.Lock()
114
+ self.timeout = timeout if timeout is not None else 30.0
115
+
116
+ async def _attempt_async(
117
+ self, operation: Callable[[], Awaitable[T]], default: T | None = None
118
+ ) -> T | None:
119
+ """Run an async operation and return default on failure.
120
+
121
+ Args:
122
+ operation (Callable[[], Awaitable[T]]): Callable object executed by the helper.
123
+ default (T | None): Fallback value returned when the operation fails. Defaults to
124
+ None.
125
+
126
+ Returns:
127
+ T | None: The result produced by the operation.
128
+ """
129
+ try:
130
+ return await operation()
131
+ except Exception:
132
+ return default
133
+
134
+ async def _attempt_async_with_error(
135
+ self, operation: Callable[[], Awaitable[T]]
136
+ ) -> tuple[T | None, Exception | None]:
137
+ """Run an async operation and return (result, error).
138
+
139
+ Args:
140
+ operation (Callable[[], Awaitable[T]]): Callable object executed by the helper.
141
+
142
+ Returns:
143
+ tuple[T | None, Exception | None]: A tuple containing the resulting values.
144
+ """
145
+ try:
146
+ return await operation(), None
147
+ except Exception as exc:
148
+ return None, exc
149
+
150
+ def _attempt_sync(
151
+ self, operation: Callable[[], T], default: T | None = None
152
+ ) -> T | None:
153
+ """Run a sync operation and return default on failure.
154
+
155
+ Args:
156
+ operation (Callable[[], T]): Callable object executed by the helper.
157
+ default (T | None): Fallback value returned when the operation fails. Defaults to
158
+ None.
159
+
160
+ Returns:
161
+ T | None: The result produced by the operation.
162
+ """
163
+ try:
164
+ return operation()
165
+ except Exception:
166
+ return default
167
+
168
+ async def _invoke_with_optional_args(
169
+ self,
170
+ adapter: SolidWorksAdapter,
171
+ method_name: str,
172
+ *args: object,
173
+ ) -> object:
174
+ """Invoke adapter method with args, retrying without args on signature mismatch.
175
+
176
+ Args:
177
+ adapter (SolidWorksAdapter): Adapter instance used for the operation.
178
+ method_name (str): Name of the method to invoke.
179
+ *args (object): Additional positional arguments forwarded to the call.
180
+
181
+ Returns:
182
+ object: The result produced by the operation.
183
+ """
184
+ method = getattr(adapter, method_name)
185
+ try:
186
+ return await method(*args)
187
+ except TypeError:
188
+ return await method()
189
+
190
+ async def _replace_failed_adapter(self) -> Exception | None:
191
+ """Create, connect, and return a replacement adapter.
192
+
193
+ Returns None on success, or the captured exception on failure.
194
+
195
+ Returns:
196
+ Exception | None: The result produced by the operation.
197
+ """
198
+ try:
199
+ new_adapter = self.adapter_factory()
200
+ await new_adapter.connect()
201
+ await self._return_adapter(new_adapter)
202
+ return None
203
+ except Exception as exc:
204
+ return exc
205
+
206
+ @property
207
+ def size(self) -> int:
208
+ """Provide size support for the connection pool adapter.
209
+
210
+ Returns:
211
+ int: The computed numeric result.
212
+ """
213
+ return len(self.pool)
214
+
215
+ @property
216
+ def active_connections(self) -> int:
217
+ """Provide active connections support for the connection pool adapter.
218
+
219
+ Returns:
220
+ int: The computed numeric result.
221
+ """
222
+ return max(0, len(self.pool) - self.available_adapters.qsize())
223
+
224
+ async def acquire(self) -> SolidWorksAdapter:
225
+ """Provide acquire support for the connection pool adapter.
226
+
227
+ Returns:
228
+ SolidWorksAdapter: The result produced by the operation.
229
+ """
230
+ return await self._get_adapter(timeout=self.timeout)
231
+
232
+ async def release(self, adapter: SolidWorksAdapter) -> None:
233
+ """Provide release support for the connection pool adapter.
234
+
235
+ Args:
236
+ adapter (SolidWorksAdapter): Adapter instance used for the operation.
237
+
238
+ Returns:
239
+ None: None.
240
+ """
241
+ await self._return_adapter(adapter)
242
+
243
+ async def cleanup(self) -> None:
244
+ """Provide cleanup support for the connection pool adapter.
245
+
246
+ Returns:
247
+ None: None.
248
+ """
249
+ await self.disconnect()
250
+
251
+ async def _initialize_pool(self) -> None:
252
+ """Initialize the connection pool.
253
+
254
+ Returns:
255
+ None: None.
256
+ """
257
+ if self.pool_initialized:
258
+ return
259
+
260
+ async with self._lock:
261
+ if self.pool_initialized:
262
+ return # type: ignore[unreachable] # double-check locking pattern
263
+
264
+ logger.info(f"Initializing connection pool with {self.pool_size} adapters")
265
+
266
+ for i in range(self.pool_size):
267
+ try:
268
+ adapter = self.adapter_factory()
269
+ await adapter.connect()
270
+ self.pool.append(adapter)
271
+ await self.available_adapters.put(adapter)
272
+ logger.debug(f"Initialized adapter {i + 1}/{self.pool_size}")
273
+ except Exception as e:
274
+ logger.warning(f"Failed to initialize adapter {i + 1}: {e}")
275
+
276
+ self.pool_initialized = True
277
+ logger.info(f"Connection pool initialized with {len(self.pool)} adapters")
278
+
279
+ async def _get_adapter(self, timeout: float = 30.0) -> SolidWorksAdapter:
280
+ """Get an available adapter from the pool.
281
+
282
+ Args:
283
+ timeout (float): Maximum time to wait in seconds. Defaults to 30.0.
284
+
285
+ Returns:
286
+ SolidWorksAdapter: The result produced by the operation.
287
+
288
+ Raises:
289
+ Exception: If the operation cannot be completed.
290
+ """
291
+ await self._initialize_pool()
292
+
293
+ try:
294
+ adapter = await asyncio.wait_for(
295
+ self.available_adapters.get(), timeout=timeout
296
+ )
297
+ return adapter
298
+ except TimeoutError as err:
299
+ raise Exception(f"No adapter available within {timeout} seconds") from err
300
+
301
+ async def _return_adapter(self, adapter: SolidWorksAdapter) -> None:
302
+ """Return an adapter to the pool.
303
+
304
+ Args:
305
+ adapter (SolidWorksAdapter): Adapter instance used for the operation.
306
+
307
+ Returns:
308
+ None: None.
309
+ """
310
+ await self.available_adapters.put(adapter)
311
+
312
+ async def _execute_with_pool(
313
+ self,
314
+ operation_name: str,
315
+ operation: Callable[[SolidWorksAdapter], Awaitable[AdapterResult[T]]],
316
+ ) -> AdapterResult[T]:
317
+ """Build internal execute with pool.
318
+
319
+ Args:
320
+ operation_name (str): The operation name value.
321
+ operation (Callable[[SolidWorksAdapter], Awaitable[AdapterResult[T]]]): Callable
322
+ object
323
+ executed by
324
+ the helper.
325
+
326
+ Returns:
327
+ AdapterResult[T]: The result produced by the operation.
328
+ """
329
+ retries = 0
330
+ last_error = None
331
+
332
+ while retries <= self.max_retries:
333
+ adapter = None
334
+ try:
335
+ adapter = await self._get_adapter()
336
+ result = await operation(adapter)
337
+
338
+ # Return adapter to pool
339
+ await self._return_adapter(adapter)
340
+
341
+ return result
342
+
343
+ except Exception as e:
344
+ last_error = e
345
+ retries += 1
346
+
347
+ logger.warning(
348
+ f"Operation {operation_name} failed (attempt {retries}): {e}"
349
+ )
350
+
351
+ if adapter:
352
+ # Don't return failed adapter to pool, create a new one
353
+ from .base import SolidWorksAdapter
354
+
355
+ typed_adapter: SolidWorksAdapter = adapter
356
+ await self._attempt_async(lambda a=typed_adapter: a.disconnect()) # type: ignore[misc]
357
+
358
+ replacement_error = await self._attempt_async(
359
+ self._replace_failed_adapter
360
+ )
361
+ if replacement_error is not None:
362
+ logger.error(
363
+ f"Failed to create replacement adapter: {replacement_error}"
364
+ )
365
+
366
+ if retries <= self.max_retries:
367
+ await asyncio.sleep(1.0 * retries) # Exponential backoff
368
+
369
+ # All retries exhausted
370
+ return AdapterResult(
371
+ status=AdapterResultStatus.ERROR,
372
+ error=f"Operation {operation_name} failed after {self.max_retries} retries: {last_error}",
373
+ )
374
+
375
+ # Adapter interface implementation
376
+
377
+ async def connect(self) -> None:
378
+ """Initialize the connection pool.
379
+
380
+ Returns:
381
+ None: None.
382
+ """
383
+ await self._initialize_pool()
384
+
385
+ async def disconnect(self) -> None:
386
+ """Disconnect all adapters in the pool.
387
+
388
+ Returns:
389
+ None: None.
390
+ """
391
+ for adapter in self.pool:
392
+ from .base import SolidWorksAdapter
393
+
394
+ typed_adapter: SolidWorksAdapter = adapter
395
+ _, error = await self._attempt_async_with_error(
396
+ lambda a=typed_adapter: a.disconnect() # type: ignore[misc]
397
+ )
398
+ if error is not None:
399
+ logger.warning(f"Error disconnecting adapter: {error}")
400
+
401
+ self.pool.clear()
402
+
403
+ # Clear the queue
404
+ while not self.available_adapters.empty():
405
+ try:
406
+ self.available_adapters.get_nowait()
407
+ except asyncio.QueueEmpty:
408
+ break
409
+
410
+ self.pool_initialized = False
411
+
412
+ def is_connected(self) -> bool:
413
+ """Check if pool is initialized.
414
+
415
+ Returns:
416
+ bool: True if connected, otherwise False.
417
+ """
418
+ return self.pool_initialized and len(self.pool) > 0
419
+
420
+ async def health_check(self) -> AdapterHealth:
421
+ """Get health status of the connection pool.
422
+
423
+ Returns:
424
+ AdapterHealth: The result produced by the operation.
425
+ """
426
+ healthy_count = 0
427
+ total_response_time = 0
428
+
429
+ if not self.pool_initialized:
430
+ return AdapterHealth(
431
+ healthy=False,
432
+ last_check=datetime.now(),
433
+ error_count=0,
434
+ success_count=0,
435
+ average_response_time=0,
436
+ connection_status="pool_not_initialized",
437
+ metrics={
438
+ "pool_size": 0,
439
+ "available_adapters": 0,
440
+ "healthy_adapters": 0,
441
+ },
442
+ )
443
+
444
+ # Check health of all adapters
445
+ for adapter in self.pool:
446
+ from .base import SolidWorksAdapter
447
+
448
+ typed_adapter: SolidWorksAdapter = adapter
449
+ health = await self._attempt_async(lambda a=typed_adapter: a.health_check()) # type: ignore[misc]
450
+ if not health:
451
+ continue
452
+ if health.healthy:
453
+ healthy_count += 1
454
+ total_response_time += health.average_response_time
455
+
456
+ avg_response_time = total_response_time / len(self.pool) if self.pool else 0
457
+
458
+ return AdapterHealth(
459
+ healthy=healthy_count > 0,
460
+ last_check=datetime.now(),
461
+ error_count=len(self.pool) - healthy_count,
462
+ success_count=healthy_count,
463
+ average_response_time=avg_response_time,
464
+ connection_status="pooled",
465
+ metrics={
466
+ "pool_size": len(self.pool),
467
+ "available_adapters": self.available_adapters.qsize(),
468
+ "healthy_adapters": healthy_count,
469
+ },
470
+ )
471
+
472
+ # Model operations
473
+
474
+ async def open_model(self, file_path: str) -> AdapterResult[SolidWorksModel]:
475
+ """Open model using pool.
476
+
477
+ Args:
478
+ file_path (str): Path to the target file.
479
+
480
+ Returns:
481
+ AdapterResult[SolidWorksModel]: The result produced by the operation.
482
+ """
483
+ return await self._execute_with_pool(
484
+ "open_model", lambda adapter: adapter.open_model(file_path)
485
+ )
486
+
487
+ async def close_model(self, save: bool = False) -> AdapterResult[None]:
488
+ """Close model using pool.
489
+
490
+ Args:
491
+ save (bool): The save value. Defaults to False.
492
+
493
+ Returns:
494
+ AdapterResult[None]: The result produced by the operation.
495
+ """
496
+ return await self._execute_with_pool(
497
+ "close_model", lambda adapter: adapter.close_model(save)
498
+ )
499
+
500
+ async def save_file(self, file_path: str | None = None) -> AdapterResult[None]:
501
+ """Save model using pool.
502
+
503
+ Args:
504
+ file_path (str | None): Path to the target file. Defaults to None.
505
+
506
+ Returns:
507
+ AdapterResult[None]: The result produced by the operation.
508
+ """
509
+ return await self._execute_with_pool(
510
+ "save_file", lambda adapter: adapter.save_file(file_path)
511
+ )
512
+
513
+ async def create_part(
514
+ self,
515
+ name: str | None = None,
516
+ units: str | None = None,
517
+ template: str | None = None,
518
+ ) -> AdapterResult[SolidWorksModel]:
519
+ """Create part using pool.
520
+
521
+ Args:
522
+ name (str | None): The name value. Defaults to None.
523
+ units (str | None): The units value. Defaults to None.
524
+ template (str | None): Template file path. Defaults to None.
525
+
526
+ Returns:
527
+ AdapterResult[SolidWorksModel]: The result produced by the operation.
528
+ """
529
+
530
+ async def _op(adapter: SolidWorksAdapter) -> AdapterResult[SolidWorksModel]:
531
+ """Build internal op.
532
+
533
+ Args:
534
+ adapter (SolidWorksAdapter): Adapter instance used for the operation.
535
+
536
+ Returns:
537
+ AdapterResult[SolidWorksModel]: The result produced by the operation.
538
+ """
539
+ if template is not None:
540
+ # No zero-arg retry: dropping the template would silently
541
+ # build the document from a different one.
542
+ return await adapter.create_part(name, units, template)
543
+ if name is None and units is None:
544
+ return await adapter.create_part()
545
+ result = await self._invoke_with_optional_args(
546
+ adapter, "create_part", name, units
547
+ )
548
+ return cast(AdapterResult[SolidWorksModel], result)
549
+
550
+ return await self._execute_with_pool("create_part", _op)
551
+
552
+ async def create_assembly(
553
+ self, name: str | None = None, template: str | None = None
554
+ ) -> AdapterResult[SolidWorksModel]:
555
+ """Create assembly using pool.
556
+
557
+ Args:
558
+ name (str | None): The name value. Defaults to None.
559
+ template (str | None): Template file path. Defaults to None.
560
+
561
+ Returns:
562
+ AdapterResult[SolidWorksModel]: The result produced by the operation.
563
+ """
564
+
565
+ async def _op(adapter: SolidWorksAdapter) -> AdapterResult[SolidWorksModel]:
566
+ """Build internal op.
567
+
568
+ Args:
569
+ adapter (SolidWorksAdapter): Adapter instance used for the operation.
570
+
571
+ Returns:
572
+ AdapterResult[SolidWorksModel]: The result produced by the operation.
573
+ """
574
+ if template is not None:
575
+ return await adapter.create_assembly(name, template)
576
+ if name is None:
577
+ return await adapter.create_assembly()
578
+ result = await self._invoke_with_optional_args(
579
+ adapter, "create_assembly", name
580
+ )
581
+ return cast(AdapterResult[SolidWorksModel], result)
582
+
583
+ return await self._execute_with_pool("create_assembly", _op)
584
+
585
+ async def create_drawing(
586
+ self, name: str | None = None, template: str | None = None
587
+ ) -> AdapterResult[SolidWorksModel]:
588
+ """Create drawing using pool.
589
+
590
+ Args:
591
+ name (str | None): The name value. Defaults to None.
592
+ template (str | None): Template file path. Defaults to None.
593
+
594
+ Returns:
595
+ AdapterResult[SolidWorksModel]: The result produced by the operation.
596
+ """
597
+ return await self._execute_with_pool(
598
+ "create_drawing", lambda adapter: adapter.create_drawing(name, template)
599
+ )
600
+
601
+ # Feature operations
602
+
603
+ async def create_extrusion(
604
+ self, params: ExtrusionParameters
605
+ ) -> AdapterResult[SolidWorksFeature]:
606
+ """Create extrusion using pool.
607
+
608
+ Args:
609
+ params (ExtrusionParameters): The params value.
610
+
611
+ Returns:
612
+ AdapterResult[SolidWorksFeature]: The result produced by the operation.
613
+ """
614
+ return await self._execute_with_pool(
615
+ "create_extrusion", lambda adapter: adapter.create_extrusion(params)
616
+ )
617
+
618
+ async def create_cut_extrude(
619
+ self, params: ExtrusionParameters
620
+ ) -> AdapterResult[SolidWorksFeature]:
621
+ """Create cut-extrude using pool."""
622
+ return await self._execute_with_pool(
623
+ "create_cut_extrude", lambda adapter: adapter.create_cut_extrude(params)
624
+ )
625
+
626
+ async def add_fillet(
627
+ self, radius: float, edge_names: list[str]
628
+ ) -> AdapterResult[SolidWorksFeature]:
629
+ """Add fillet using pool."""
630
+ return await self._execute_with_pool(
631
+ "add_fillet", lambda adapter: adapter.add_fillet(radius, edge_names)
632
+ )
633
+
634
+ async def add_chamfer(
635
+ self, distance: float, edge_names: list[str]
636
+ ) -> AdapterResult[SolidWorksFeature]:
637
+ """Add chamfer using pool."""
638
+ return await self._execute_with_pool(
639
+ "add_chamfer", lambda adapter: adapter.add_chamfer(distance, edge_names)
640
+ )
641
+
642
+ async def get_selected_entities(self) -> AdapterResult[list[dict[str, Any]]]:
643
+ """Report the current UI selection using pool."""
644
+ return await self._execute_with_pool(
645
+ "get_selected_entities", lambda adapter: adapter.get_selected_entities()
646
+ )
647
+
648
+ async def select_feature(
649
+ self, feature_name: str, append: bool = False
650
+ ) -> AdapterResult[dict[str, Any]]:
651
+ """Select a named feature using pool."""
652
+ return await self._execute_with_pool(
653
+ "select_feature",
654
+ lambda adapter: adapter.select_feature(feature_name, append),
655
+ )
656
+
657
+ async def select_face_edges(
658
+ self,
659
+ point: list[float] | None = None,
660
+ side: str | None = None,
661
+ plane: str | None = None,
662
+ edge_type: str = "all",
663
+ append: bool = False,
664
+ ) -> AdapterResult[dict[str, Any]]:
665
+ """Multi-select a face's edges using pool."""
666
+ return await self._execute_with_pool(
667
+ "select_face_edges",
668
+ lambda adapter: adapter.select_face_edges(
669
+ point, side, plane, edge_type, append
670
+ ),
671
+ )
672
+
673
+ async def rebuild_model(
674
+ self, top_level_only: bool = False
675
+ ) -> AdapterResult[dict[str, Any]]:
676
+ """Force a rebuild using pool."""
677
+ return await self._execute_with_pool(
678
+ "rebuild_model", lambda adapter: adapter.rebuild_model(top_level_only)
679
+ )
680
+
681
+ async def create_reference_plane(
682
+ self,
683
+ reference: str,
684
+ offset: float = 0.0,
685
+ angle: float = 0.0,
686
+ flip: bool = False,
687
+ ) -> AdapterResult[dict[str, Any]]:
688
+ """Create reference plane using pool."""
689
+ return await self._execute_with_pool(
690
+ "create_reference_plane",
691
+ lambda adapter: adapter.create_reference_plane(
692
+ reference, offset, angle, flip
693
+ ),
694
+ )
695
+
696
+ async def create_axis(self, reference: str) -> AdapterResult[dict[str, Any]]:
697
+ """Create reference axis using pool."""
698
+ return await self._execute_with_pool(
699
+ "create_axis", lambda adapter: adapter.create_axis(reference)
700
+ )
701
+
702
+ async def create_reference_point(
703
+ self,
704
+ mode: str,
705
+ x: float,
706
+ y: float,
707
+ z: float,
708
+ distance: float | None = None,
709
+ percent: float | None = None,
710
+ ) -> AdapterResult[dict[str, Any]]:
711
+ """Create a reference point using pool."""
712
+ return await self._execute_with_pool(
713
+ "create_reference_point",
714
+ lambda adapter: adapter.create_reference_point(
715
+ mode, x, y, z, distance, percent
716
+ ),
717
+ )
718
+
719
+ async def mirror_feature(
720
+ self,
721
+ features: list[str],
722
+ mirror_plane: str,
723
+ merge: bool = True,
724
+ mirror_bodies: bool = True,
725
+ ) -> AdapterResult[dict[str, Any]]:
726
+ """Mirror solid bodies or features using pool."""
727
+ return await self._execute_with_pool(
728
+ "mirror_feature",
729
+ lambda adapter: adapter.mirror_feature(
730
+ features, mirror_plane, merge, mirror_bodies
731
+ ),
732
+ )
733
+
734
+ async def pattern_circular(
735
+ self,
736
+ features: list[str],
737
+ axis: str,
738
+ count: int,
739
+ angle: float = 360.0,
740
+ equal_spacing: bool = True,
741
+ ) -> AdapterResult[dict[str, Any]]:
742
+ """Pattern features around an axis using pool."""
743
+ return await self._execute_with_pool(
744
+ "pattern_circular",
745
+ lambda adapter: adapter.pattern_circular(
746
+ features, axis, count, angle, equal_spacing
747
+ ),
748
+ )
749
+
750
+ async def create_revolve(
751
+ self, params: RevolveParameters
752
+ ) -> AdapterResult[SolidWorksFeature]:
753
+ """Create revolve using pool.
754
+
755
+ Args:
756
+ params (RevolveParameters): The params value.
757
+
758
+ Returns:
759
+ AdapterResult[SolidWorksFeature]: The result produced by the operation.
760
+ """
761
+ return await self._execute_with_pool(
762
+ "create_revolve", lambda adapter: adapter.create_revolve(params)
763
+ )
764
+
765
+ async def create_sweep(
766
+ self, params: SweepParameters
767
+ ) -> AdapterResult[SolidWorksFeature]:
768
+ """Create sweep using pool.
769
+
770
+ Args:
771
+ params (SweepParameters): The params value.
772
+
773
+ Returns:
774
+ AdapterResult[SolidWorksFeature]: The result produced by the operation.
775
+ """
776
+ return await self._execute_with_pool(
777
+ "create_sweep", lambda adapter: adapter.create_sweep(params)
778
+ )
779
+
780
+ async def create_loft(
781
+ self, params: LoftParameters
782
+ ) -> AdapterResult[SolidWorksFeature]:
783
+ """Create loft using pool.
784
+
785
+ Args:
786
+ params (LoftParameters): The params value.
787
+
788
+ Returns:
789
+ AdapterResult[SolidWorksFeature]: The result produced by the operation.
790
+ """
791
+ return await self._execute_with_pool(
792
+ "create_loft", lambda adapter: adapter.create_loft(params)
793
+ )
794
+
795
+ # Sketch operations
796
+
797
+ async def create_sketch(self, plane: str) -> AdapterResult[str]:
798
+ """Create sketch using pool.
799
+
800
+ Args:
801
+ plane (str): The plane value.
802
+
803
+ Returns:
804
+ AdapterResult[str]: The result produced by the operation.
805
+ """
806
+ return await self._execute_with_pool(
807
+ "create_sketch", lambda adapter: adapter.create_sketch(plane)
808
+ )
809
+
810
+ async def add_line(
811
+ self, x1: float, y1: float, x2: float, y2: float
812
+ ) -> AdapterResult[str]:
813
+ """Add line using pool.
814
+
815
+ Args:
816
+ x1 (float): The x1 value.
817
+ y1 (float): The y1 value.
818
+ x2 (float): The x2 value.
819
+ y2 (float): The y2 value.
820
+
821
+ Returns:
822
+ AdapterResult[str]: The result produced by the operation.
823
+ """
824
+ return await self._execute_with_pool(
825
+ "add_line", lambda adapter: adapter.add_line(x1, y1, x2, y2)
826
+ )
827
+
828
+ async def add_centerline(
829
+ self, x1: float, y1: float, x2: float, y2: float
830
+ ) -> AdapterResult[str]:
831
+ """Add centerline using pool.
832
+
833
+ Args:
834
+ x1 (float): The x1 value.
835
+ y1 (float): The y1 value.
836
+ x2 (float): The x2 value.
837
+ y2 (float): The y2 value.
838
+
839
+ Returns:
840
+ AdapterResult[str]: The result produced by the operation.
841
+ """
842
+ return await self._execute_with_pool(
843
+ "add_centerline",
844
+ lambda adapter: adapter.add_centerline(x1, y1, x2, y2),
845
+ )
846
+
847
+ async def add_circle(
848
+ self, center_x: float, center_y: float, radius: float
849
+ ) -> AdapterResult[str]:
850
+ """Add circle using pool.
851
+
852
+ Args:
853
+ center_x (float): The center x value.
854
+ center_y (float): The center y value.
855
+ radius (float): The radius value.
856
+
857
+ Returns:
858
+ AdapterResult[str]: The result produced by the operation.
859
+ """
860
+ return await self._execute_with_pool(
861
+ "add_circle", lambda adapter: adapter.add_circle(center_x, center_y, radius)
862
+ )
863
+
864
+ async def add_rectangle(
865
+ self, x1: float, y1: float, x2: float, y2: float
866
+ ) -> AdapterResult[str]:
867
+ """Add rectangle using pool.
868
+
869
+ Args:
870
+ x1 (float): The x1 value.
871
+ y1 (float): The y1 value.
872
+ x2 (float): The x2 value.
873
+ y2 (float): The y2 value.
874
+
875
+ Returns:
876
+ AdapterResult[str]: The result produced by the operation.
877
+ """
878
+ return await self._execute_with_pool(
879
+ "add_rectangle", lambda adapter: adapter.add_rectangle(x1, y1, x2, y2)
880
+ )
881
+
882
+ async def add_arc(
883
+ self,
884
+ center_x: float,
885
+ center_y: float,
886
+ start_x: float,
887
+ start_y: float,
888
+ end_x: float,
889
+ end_y: float,
890
+ ) -> AdapterResult[str]:
891
+ """Add arc using pool.
892
+
893
+ Args:
894
+ center_x (float): Arc center X coordinate.
895
+ center_y (float): Arc center Y coordinate.
896
+ start_x (float): Arc start X coordinate.
897
+ start_y (float): Arc start Y coordinate.
898
+ end_x (float): Arc end X coordinate.
899
+ end_y (float): Arc end Y coordinate.
900
+
901
+ Returns:
902
+ AdapterResult[str]: The result produced by the operation.
903
+ """
904
+ return await self._execute_with_pool(
905
+ "add_arc",
906
+ lambda adapter: adapter.add_arc(
907
+ center_x,
908
+ center_y,
909
+ start_x,
910
+ start_y,
911
+ end_x,
912
+ end_y,
913
+ ),
914
+ )
915
+
916
+ async def add_spline(self, points: list[dict[str, float]]) -> AdapterResult[str]:
917
+ """Add spline using pool.
918
+
919
+ Args:
920
+ points (list[dict[str, float]]): The points value.
921
+
922
+ Returns:
923
+ AdapterResult[str]: The result produced by the operation.
924
+ """
925
+ return await self._execute_with_pool(
926
+ "add_spline", lambda adapter: adapter.add_spline(points)
927
+ )
928
+
929
+ async def add_polygon(
930
+ self, center_x: float, center_y: float, radius: float, sides: int
931
+ ) -> AdapterResult[str]:
932
+ """Add polygon using pool.
933
+
934
+ Args:
935
+ center_x (float): The center x value.
936
+ center_y (float): The center y value.
937
+ radius (float): The radius value.
938
+ sides (int): The sides value.
939
+
940
+ Returns:
941
+ AdapterResult[str]: The result produced by the operation.
942
+ """
943
+ return await self._execute_with_pool(
944
+ "add_polygon",
945
+ lambda adapter: adapter.add_polygon(center_x, center_y, radius, sides),
946
+ )
947
+
948
+ async def add_ellipse(
949
+ self,
950
+ center_x: float,
951
+ center_y: float,
952
+ major_axis: float,
953
+ minor_axis: float,
954
+ ) -> AdapterResult[str]:
955
+ """Add ellipse using pool.
956
+
957
+ Args:
958
+ center_x (float): The center x value.
959
+ center_y (float): The center y value.
960
+ major_axis (float): The major axis value.
961
+ minor_axis (float): The minor axis value.
962
+
963
+ Returns:
964
+ AdapterResult[str]: The result produced by the operation.
965
+ """
966
+ return await self._execute_with_pool(
967
+ "add_ellipse",
968
+ lambda adapter: adapter.add_ellipse(
969
+ center_x, center_y, major_axis, minor_axis
970
+ ),
971
+ )
972
+
973
+ async def sketch_linear_pattern(
974
+ self,
975
+ entities: list[str],
976
+ direction_x: float,
977
+ direction_y: float,
978
+ spacing: float,
979
+ count: int,
980
+ ) -> AdapterResult[str]:
981
+ """Sketch linear pattern using pool.
982
+
983
+ Args:
984
+ entities (list[str]): The entities value.
985
+ direction_x (float): The direction x value.
986
+ direction_y (float): The direction y value.
987
+ spacing (float): The spacing value.
988
+ count (int): The count value.
989
+
990
+ Returns:
991
+ AdapterResult[str]: The result produced by the operation.
992
+ """
993
+ return await self._execute_with_pool(
994
+ "sketch_linear_pattern",
995
+ lambda adapter: adapter.sketch_linear_pattern(
996
+ entities, direction_x, direction_y, spacing, count
997
+ ),
998
+ )
999
+
1000
+ async def sketch_circular_pattern(
1001
+ self,
1002
+ entities: list[str],
1003
+ angle: float,
1004
+ count: int,
1005
+ ) -> AdapterResult[str]:
1006
+ """Sketch circular pattern using pool.
1007
+
1008
+ Args:
1009
+ entities (list[str]): The entities value.
1010
+ angle (float): The angle value.
1011
+ count (int): The count value.
1012
+
1013
+ Returns:
1014
+ AdapterResult[str]: The result produced by the operation.
1015
+ """
1016
+ return await self._execute_with_pool(
1017
+ "sketch_circular_pattern",
1018
+ lambda adapter: adapter.sketch_circular_pattern(entities, angle, count),
1019
+ )
1020
+
1021
+ async def sketch_mirror(
1022
+ self, entities: list[str], mirror_line: str
1023
+ ) -> AdapterResult[str]:
1024
+ """Sketch mirror using pool.
1025
+
1026
+ Args:
1027
+ entities (list[str]): The entities value.
1028
+ mirror_line (str): The mirror line value.
1029
+
1030
+ Returns:
1031
+ AdapterResult[str]: The result produced by the operation.
1032
+ """
1033
+ return await self._execute_with_pool(
1034
+ "sketch_mirror",
1035
+ lambda adapter: adapter.sketch_mirror(entities, mirror_line),
1036
+ )
1037
+
1038
+ async def sketch_offset(
1039
+ self,
1040
+ entities: list[str],
1041
+ offset_distance: float,
1042
+ reverse_direction: bool,
1043
+ ) -> AdapterResult[str]:
1044
+ """Sketch offset using pool.
1045
+
1046
+ Args:
1047
+ entities (list[str]): The entities value.
1048
+ offset_distance (float): The offset distance value.
1049
+ reverse_direction (bool): The reverse direction value.
1050
+
1051
+ Returns:
1052
+ AdapterResult[str]: The result produced by the operation.
1053
+ """
1054
+ return await self._execute_with_pool(
1055
+ "sketch_offset",
1056
+ lambda adapter: adapter.sketch_offset(
1057
+ entities, offset_distance, reverse_direction
1058
+ ),
1059
+ )
1060
+
1061
+ async def add_sketch_constraint(
1062
+ self,
1063
+ entity1: str,
1064
+ entity2: str | None,
1065
+ relation_type: str,
1066
+ entity3: str | None = None,
1067
+ ) -> AdapterResult[str]:
1068
+ """Add sketch constraint using pool."""
1069
+ return await self._execute_with_pool(
1070
+ "add_sketch_constraint",
1071
+ lambda adapter: adapter.add_sketch_constraint(
1072
+ entity1,
1073
+ entity2,
1074
+ relation_type,
1075
+ entity3,
1076
+ ),
1077
+ )
1078
+
1079
+ async def add_sketch_dimension(
1080
+ self,
1081
+ entity1: str,
1082
+ entity2: str | None,
1083
+ dimension_type: str,
1084
+ value: float,
1085
+ ) -> AdapterResult[str]:
1086
+ """Add sketch dimension using pool."""
1087
+ return await self._execute_with_pool(
1088
+ "add_sketch_dimension",
1089
+ lambda adapter: adapter.add_sketch_dimension(
1090
+ entity1,
1091
+ entity2,
1092
+ dimension_type,
1093
+ value,
1094
+ ),
1095
+ )
1096
+
1097
+ async def check_sketch_fully_defined(
1098
+ self, sketch_name: str | None = None
1099
+ ) -> AdapterResult[dict[str, Any]]:
1100
+ """Check sketch definition status using pool."""
1101
+ return await self._execute_with_pool(
1102
+ "check_sketch_fully_defined",
1103
+ lambda adapter: adapter.check_sketch_fully_defined(sketch_name),
1104
+ )
1105
+
1106
+ async def exit_sketch(self) -> AdapterResult[None]:
1107
+ """Exit sketch using pool.
1108
+
1109
+ Returns:
1110
+ AdapterResult[None]: The result produced by the operation.
1111
+ """
1112
+ return await self._execute_with_pool(
1113
+ "exit_sketch", lambda adapter: adapter.exit_sketch()
1114
+ )
1115
+
1116
+ # Analysis operations
1117
+
1118
+ async def get_mass_properties(self) -> AdapterResult[MassProperties]:
1119
+ """Get mass properties using pool.
1120
+
1121
+ Returns:
1122
+ AdapterResult[MassProperties]: The result produced by the operation.
1123
+ """
1124
+ return await self._execute_with_pool(
1125
+ "get_mass_properties", lambda adapter: adapter.get_mass_properties()
1126
+ )
1127
+
1128
+ async def get_model_info(self) -> AdapterResult[dict[str, object]]:
1129
+ """Get active model metadata using pool.
1130
+
1131
+ Returns:
1132
+ AdapterResult[dict[str, object]]: The result produced by the operation.
1133
+ """
1134
+ return await self._execute_with_pool(
1135
+ "get_model_info", lambda adapter: adapter.get_model_info()
1136
+ )
1137
+
1138
+ async def list_features(
1139
+ self, include_suppressed: bool = False, max_assembly_depth: int = 2
1140
+ ) -> AdapterResult[list[dict[str, object]]]:
1141
+ """List model features using pool.
1142
+
1143
+ Args:
1144
+ include_suppressed (bool): The include suppressed value. Defaults to False.
1145
+ max_assembly_depth (int): Sub-assembly recursion depth. Defaults to 2.
1146
+
1147
+ Returns:
1148
+ AdapterResult[list[dict[str, object]]]: The result produced by the operation.
1149
+ """
1150
+ return await self._execute_with_pool(
1151
+ "list_features",
1152
+ lambda adapter: adapter.list_features(
1153
+ include_suppressed, max_assembly_depth
1154
+ ),
1155
+ )
1156
+
1157
+ async def list_configurations(self) -> AdapterResult[list[str]]:
1158
+ """List model configurations using pool.
1159
+
1160
+ Returns:
1161
+ AdapterResult[list[str]]: The result produced by the operation.
1162
+ """
1163
+ return await self._execute_with_pool(
1164
+ "list_configurations", lambda adapter: adapter.list_configurations()
1165
+ )
1166
+
1167
+ async def execute_macro(
1168
+ self, params: dict[str, Any]
1169
+ ) -> AdapterResult[dict[str, Any]]:
1170
+ """Provide execute macro support for the connection pool adapter.
1171
+
1172
+ Args:
1173
+ params (dict[str, Any]): The params value.
1174
+
1175
+ Returns:
1176
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1177
+ """
1178
+ return await self._execute_with_pool(
1179
+ "execute_macro",
1180
+ lambda adapter: adapter.execute_macro(params), # type: ignore[attr-defined]
1181
+ )
1182
+
1183
+ # Export operations
1184
+
1185
+ async def export_image(self, payload: dict) -> AdapterResult[dict]:
1186
+ """Export viewport image using pool.
1187
+
1188
+ Args:
1189
+ payload (dict): The payload value.
1190
+
1191
+ Returns:
1192
+ AdapterResult[dict]: The result produced by the operation.
1193
+ """
1194
+ return await self._execute_with_pool(
1195
+ "export_image", lambda adapter: adapter.export_image(payload)
1196
+ )
1197
+
1198
+ async def export_file(
1199
+ self, file_path: str, format_type: str
1200
+ ) -> AdapterResult[None]:
1201
+ """Export file using pool.
1202
+
1203
+ Args:
1204
+ file_path (str): Path to the target file.
1205
+ format_type (str): The format type value.
1206
+
1207
+ Returns:
1208
+ AdapterResult[None]: The result produced by the operation.
1209
+ """
1210
+ return await self._execute_with_pool(
1211
+ "export_file", lambda adapter: adapter.export_file(file_path, format_type)
1212
+ )
1213
+
1214
+ # Dimension operations
1215
+
1216
+ async def get_dimension(self, name: str) -> AdapterResult[float]:
1217
+ """Get dimension using pool.
1218
+
1219
+ Args:
1220
+ name (str): The name value.
1221
+
1222
+ Returns:
1223
+ AdapterResult[float]: The result produced by the operation.
1224
+ """
1225
+ return await self._execute_with_pool(
1226
+ "get_dimension", lambda adapter: adapter.get_dimension(name)
1227
+ )
1228
+
1229
+ async def set_dimension(self, name: str, value: float) -> AdapterResult[None]:
1230
+ """Set dimension using pool.
1231
+
1232
+ Args:
1233
+ name (str): The name value.
1234
+ value (float): The value value.
1235
+
1236
+ Returns:
1237
+ AdapterResult[None]: The result produced by the operation.
1238
+ """
1239
+ return await self._execute_with_pool(
1240
+ "set_dimension", lambda adapter: adapter.set_dimension(name, value)
1241
+ )
1242
+
1243
+ async def set_units(self, unit_system: str) -> AdapterResult[dict[str, Any]]:
1244
+ """Set document units using pool.
1245
+
1246
+ Args:
1247
+ unit_system (str): One of ``mm``, ``cm``, ``m``, ``in``, ``ft``.
1248
+
1249
+ Returns:
1250
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1251
+ """
1252
+ return await self._execute_with_pool(
1253
+ "set_units", lambda adapter: adapter.set_units(unit_system)
1254
+ )
1255
+
1256
+ async def list_open_documents(self) -> AdapterResult[list[dict[str, Any]]]:
1257
+ """List open documents using pool.
1258
+
1259
+ Returns:
1260
+ AdapterResult[list[dict[str, Any]]]: The result produced by the
1261
+ operation.
1262
+ """
1263
+ return await self._execute_with_pool(
1264
+ "list_open_documents", lambda adapter: adapter.list_open_documents()
1265
+ )
1266
+
1267
+ async def activate_document(
1268
+ self, title_or_path: str
1269
+ ) -> AdapterResult[dict[str, Any]]:
1270
+ """Activate an open document using pool.
1271
+
1272
+ Args:
1273
+ title_or_path (str): Title, full path, or file name of an open
1274
+ document.
1275
+
1276
+ Returns:
1277
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1278
+ """
1279
+ return await self._execute_with_pool(
1280
+ "activate_document",
1281
+ lambda adapter: adapter.activate_document(title_or_path),
1282
+ )
1283
+
1284
+ # Assembly operations
1285
+
1286
+ async def insert_component(
1287
+ self, file_path: str, x: float = 0.0, y: float = 0.0, z: float = 0.0
1288
+ ) -> AdapterResult[dict[str, Any]]:
1289
+ """Insert component using pool.
1290
+
1291
+ Args:
1292
+ file_path (str): Path to the target file.
1293
+ x (float): X position in millimetres. Defaults to 0.0.
1294
+ y (float): Y position in millimetres. Defaults to 0.0.
1295
+ z (float): Z position in millimetres. Defaults to 0.0.
1296
+
1297
+ Returns:
1298
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1299
+ """
1300
+ return await self._execute_with_pool(
1301
+ "insert_component",
1302
+ lambda adapter: adapter.insert_component(file_path, x, y, z),
1303
+ )
1304
+
1305
+ async def list_components(self) -> AdapterResult[list[str]]:
1306
+ """List components using pool.
1307
+
1308
+ Returns:
1309
+ AdapterResult[list[str]]: The result produced by the operation.
1310
+ """
1311
+ return await self._execute_with_pool(
1312
+ "list_components", lambda adapter: adapter.list_components()
1313
+ )
1314
+
1315
+ async def get_model_geometry_summary(self) -> AdapterResult[dict[str, Any]]:
1316
+ """Summarise the active document using pool.
1317
+
1318
+ Returns:
1319
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1320
+ """
1321
+ return await self._execute_with_pool(
1322
+ "get_model_geometry_summary",
1323
+ lambda adapter: adapter.get_model_geometry_summary(),
1324
+ )
1325
+
1326
+ async def create_drawing_view(
1327
+ self, payload: Any = None
1328
+ ) -> AdapterResult[dict[str, Any]]:
1329
+ """Create a drawing view using pool.
1330
+
1331
+ Args:
1332
+ payload (Any): Tool payload for the drawing view.
1333
+
1334
+ Returns:
1335
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1336
+ """
1337
+ return await self._execute_with_pool(
1338
+ "create_drawing_view", lambda adapter: adapter.create_drawing_view(payload)
1339
+ )
1340
+
1341
+ async def add_drawing_view(
1342
+ self, payload: Any = None
1343
+ ) -> AdapterResult[dict[str, Any]]:
1344
+ """Add a drawing view using pool.
1345
+
1346
+ Args:
1347
+ payload (Any): Tool payload for the drawing view.
1348
+
1349
+ Returns:
1350
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1351
+ """
1352
+ return await self._execute_with_pool(
1353
+ "add_drawing_view", lambda adapter: adapter.add_drawing_view(payload)
1354
+ )
1355
+
1356
+ async def create_technical_drawing(
1357
+ self, payload: Any = None
1358
+ ) -> AdapterResult[dict[str, Any]]:
1359
+ """Create standard views using pool.
1360
+
1361
+ Args:
1362
+ payload (Any): Tool payload for the technical drawing.
1363
+
1364
+ Returns:
1365
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1366
+ """
1367
+ return await self._execute_with_pool(
1368
+ "create_technical_drawing",
1369
+ lambda adapter: adapter.create_technical_drawing(payload),
1370
+ )
1371
+
1372
+ async def add_note(self, payload: Any = None) -> AdapterResult[dict[str, Any]]:
1373
+ """Add a drawing note using pool.
1374
+
1375
+ Args:
1376
+ payload (Any): Tool payload for the note.
1377
+
1378
+ Returns:
1379
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1380
+ """
1381
+ return await self._execute_with_pool(
1382
+ "add_note", lambda adapter: adapter.add_note(payload)
1383
+ )
1384
+
1385
+ async def list_drawing_views(self) -> AdapterResult[list[str]]:
1386
+ """List drawing views using pool.
1387
+
1388
+ Returns:
1389
+ AdapterResult[list[str]]: The result produced by the operation.
1390
+ """
1391
+ return await self._execute_with_pool(
1392
+ "list_drawing_views", lambda adapter: adapter.list_drawing_views()
1393
+ )
1394
+
1395
+ async def auto_center_marks(
1396
+ self,
1397
+ view_name: str,
1398
+ mark_holes: bool = True,
1399
+ mark_fillets: bool = False,
1400
+ mark_slots: bool = True,
1401
+ ) -> AdapterResult[dict[str, Any]]:
1402
+ """Auto-insert drawing centre marks using pool."""
1403
+ return await self._execute_with_pool(
1404
+ "auto_center_marks",
1405
+ lambda adapter: adapter.auto_center_marks(
1406
+ view_name, mark_holes, mark_fillets, mark_slots
1407
+ ),
1408
+ )
1409
+
1410
+ async def save_body_as_part(
1411
+ self, body_name: str, file_path: str
1412
+ ) -> AdapterResult[dict[str, Any]]:
1413
+ """Save a body to a new part using pool."""
1414
+ return await self._execute_with_pool(
1415
+ "save_body_as_part",
1416
+ lambda adapter: adapter.save_body_as_part(body_name, file_path),
1417
+ )
1418
+
1419
+ async def check_interference(
1420
+ self, params: Any = None
1421
+ ) -> AdapterResult[dict[str, Any]]:
1422
+ """Check interference using pool.
1423
+
1424
+ Args:
1425
+ params (Any): Optional interference-detection settings.
1426
+
1427
+ Returns:
1428
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1429
+ """
1430
+ return await self._execute_with_pool(
1431
+ "check_interference", lambda adapter: adapter.check_interference(params)
1432
+ )
1433
+
1434
+ async def delete_feature(self, name: str) -> AdapterResult[dict[str, Any]]:
1435
+ """Delete a feature using pool.
1436
+
1437
+ Args:
1438
+ name (str): Feature or sketch name.
1439
+
1440
+ Returns:
1441
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1442
+ """
1443
+ return await self._execute_with_pool(
1444
+ "delete_feature", lambda adapter: adapter.delete_feature(name)
1445
+ )
1446
+
1447
+ async def suppress_feature(
1448
+ self, name: str, suppress: bool = True
1449
+ ) -> AdapterResult[dict[str, Any]]:
1450
+ """Suppress or unsuppress a feature using pool.
1451
+
1452
+ Args:
1453
+ name (str): Feature name.
1454
+ suppress (bool): True to suppress, False to unsuppress.
1455
+
1456
+ Returns:
1457
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1458
+ """
1459
+ return await self._execute_with_pool(
1460
+ "suppress_feature",
1461
+ lambda adapter: adapter.suppress_feature(name, suppress),
1462
+ )
1463
+
1464
+ async def rename_feature(
1465
+ self, old_name: str, new_name: str
1466
+ ) -> AdapterResult[dict[str, Any]]:
1467
+ """Rename a feature using pool.
1468
+
1469
+ Args:
1470
+ old_name (str): Current feature name.
1471
+ new_name (str): New feature name.
1472
+
1473
+ Returns:
1474
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1475
+ """
1476
+ return await self._execute_with_pool(
1477
+ "rename_feature",
1478
+ lambda adapter: adapter.rename_feature(old_name, new_name),
1479
+ )
1480
+
1481
+ async def undo(self, count: int = 1) -> AdapterResult[dict[str, Any]]:
1482
+ """Undo using pool.
1483
+
1484
+ Args:
1485
+ count (int): Number of steps to undo.
1486
+
1487
+ Returns:
1488
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1489
+ """
1490
+ return await self._execute_with_pool(
1491
+ "undo", lambda adapter: adapter.undo(count)
1492
+ )
1493
+
1494
+ async def add_mate(
1495
+ self,
1496
+ component_a: str,
1497
+ component_b: str,
1498
+ entity_a: str = "Front Plane",
1499
+ entity_b: str = "Front Plane",
1500
+ mate_type: str = "coincident",
1501
+ alignment: str = "aligned",
1502
+ distance: float = 0.0,
1503
+ angle: float = 0.0,
1504
+ ) -> AdapterResult[dict[str, Any]]:
1505
+ """Add mate using pool.
1506
+
1507
+ Args:
1508
+ component_a (str): First component instance name.
1509
+ component_b (str): Second component instance name.
1510
+ entity_a (str): Named feature on the first component. Defaults to
1511
+ "Front Plane".
1512
+ entity_b (str): Named feature on the second component. Defaults to
1513
+ "Front Plane".
1514
+ mate_type (str): Mate type. Defaults to "coincident".
1515
+ alignment (str): Mate alignment. Defaults to "aligned".
1516
+ distance (float): Distance in millimetres. Defaults to 0.0.
1517
+ angle (float): Angle in degrees. Defaults to 0.0.
1518
+
1519
+ Returns:
1520
+ AdapterResult[dict[str, Any]]: The result produced by the operation.
1521
+ """
1522
+ return await self._execute_with_pool(
1523
+ "add_mate",
1524
+ lambda adapter: adapter.add_mate(
1525
+ component_a,
1526
+ component_b,
1527
+ entity_a,
1528
+ entity_b,
1529
+ mate_type,
1530
+ alignment,
1531
+ distance,
1532
+ angle,
1533
+ ),
1534
+ )
1535
+
1536
+ # --- Engineering-data and drawing-documentation methods ---
1537
+
1538
+ async def list_model_dimensions(
1539
+ self,
1540
+ feature_name: str | None = None,
1541
+ ) -> AdapterResult[list[dict[str, Any]]]:
1542
+ """List every dimension in the active part or assembly using pool."""
1543
+ return await self._execute_with_pool(
1544
+ "list_model_dimensions",
1545
+ lambda adapter: adapter.list_model_dimensions(feature_name),
1546
+ )
1547
+
1548
+ async def measure_entities(
1549
+ self,
1550
+ entities: list[str],
1551
+ ) -> AdapterResult[dict[str, Any]]:
1552
+ """Measure one or two selected entities using pool."""
1553
+ return await self._execute_with_pool(
1554
+ "measure_entities",
1555
+ lambda adapter: adapter.measure_entities(entities),
1556
+ )
1557
+
1558
+ async def get_material(
1559
+ self,
1560
+ configuration: str | None = None,
1561
+ ) -> AdapterResult[dict[str, Any]]:
1562
+ """Read the material assigned to the active part using pool."""
1563
+ return await self._execute_with_pool(
1564
+ "get_material",
1565
+ lambda adapter: adapter.get_material(configuration),
1566
+ )
1567
+
1568
+ async def set_material(
1569
+ self,
1570
+ material_name: str,
1571
+ database: str | None = None,
1572
+ configuration: str | None = None,
1573
+ ) -> AdapterResult[dict[str, Any]]:
1574
+ """Assign a material to the active part using pool."""
1575
+ return await self._execute_with_pool(
1576
+ "set_material",
1577
+ lambda adapter: adapter.set_material(
1578
+ material_name, database, configuration
1579
+ ),
1580
+ )
1581
+
1582
+ async def list_available_materials(
1583
+ self,
1584
+ search: str | None = None,
1585
+ ) -> AdapterResult[list[dict[str, str]]]:
1586
+ """List materials from the configured material libraries using pool."""
1587
+ return await self._execute_with_pool(
1588
+ "list_available_materials",
1589
+ lambda adapter: adapter.list_available_materials(search),
1590
+ )
1591
+
1592
+ async def get_custom_properties(
1593
+ self,
1594
+ configuration: str | None = None,
1595
+ ) -> AdapterResult[dict[str, Any]]:
1596
+ """Read the custom properties of the active document using pool."""
1597
+ return await self._execute_with_pool(
1598
+ "get_custom_properties",
1599
+ lambda adapter: adapter.get_custom_properties(configuration),
1600
+ )
1601
+
1602
+ async def set_custom_property(
1603
+ self,
1604
+ name: str,
1605
+ value: str,
1606
+ configuration: str | None = None,
1607
+ ) -> AdapterResult[dict[str, Any]]:
1608
+ """Create or overwrite one custom property using pool."""
1609
+ return await self._execute_with_pool(
1610
+ "set_custom_property",
1611
+ lambda adapter: adapter.set_custom_property(name, value, configuration),
1612
+ )
1613
+
1614
+ async def export_flat_pattern(
1615
+ self,
1616
+ file_path: str,
1617
+ ) -> AdapterResult[dict[str, Any]]:
1618
+ """Export the active sheet-metal part's flat pattern using pool."""
1619
+ return await self._execute_with_pool(
1620
+ "export_flat_pattern",
1621
+ lambda adapter: adapter.export_flat_pattern(file_path),
1622
+ )
1623
+
1624
+ async def insert_model_dimensions(
1625
+ self,
1626
+ view_name: str | None = None,
1627
+ include_hole_wizard: bool = True,
1628
+ ) -> AdapterResult[dict[str, Any]]:
1629
+ """Bring model dimensions into drawing views using pool."""
1630
+ return await self._execute_with_pool(
1631
+ "insert_model_dimensions",
1632
+ lambda adapter: adapter.insert_model_dimensions(
1633
+ view_name, include_hole_wizard
1634
+ ),
1635
+ )
1636
+
1637
+ async def arrange_dimensions(
1638
+ self,
1639
+ view_name: str | None = None,
1640
+ ) -> AdapterResult[dict[str, Any]]:
1641
+ """Move drawing dimensions so none overlaps, then verify using pool."""
1642
+ return await self._execute_with_pool(
1643
+ "arrange_dimensions",
1644
+ lambda adapter: adapter.arrange_dimensions(view_name),
1645
+ )
1646
+
1647
+ async def insert_bom_table(
1648
+ self,
1649
+ view_name: str,
1650
+ template_path: str | None = None,
1651
+ bom_type: str = "top_level_only",
1652
+ x_mm: float | None = None,
1653
+ y_mm: float | None = None,
1654
+ ) -> AdapterResult[dict[str, Any]]:
1655
+ """Insert a BOM table anchored to an assembly drawing view using pool."""
1656
+ return await self._execute_with_pool(
1657
+ "insert_bom_table",
1658
+ lambda adapter: adapter.insert_bom_table(
1659
+ view_name, template_path, bom_type, x_mm, y_mm
1660
+ ),
1661
+ )
1662
+
1663
+ async def set_sheet_scale(
1664
+ self,
1665
+ numerator: float,
1666
+ denominator: float,
1667
+ ) -> AdapterResult[dict[str, Any]]:
1668
+ """Set the active drawing sheet's scale using pool."""
1669
+ return await self._execute_with_pool(
1670
+ "set_sheet_scale",
1671
+ lambda adapter: adapter.set_sheet_scale(numerator, denominator),
1672
+ )
1673
+
1674
+ async def add_gtol(
1675
+ self,
1676
+ characteristic: str,
1677
+ tolerance: float,
1678
+ x_mm: float,
1679
+ y_mm: float,
1680
+ diameter_zone: bool = False,
1681
+ material_condition: str = "none",
1682
+ datums: list[str] | None = None,
1683
+ attach_at_mm: tuple[float, float] | None = None,
1684
+ dimension: tuple[str, str] | None = None,
1685
+ ) -> AdapterResult[dict[str, Any]]:
1686
+ """Add a GD&T feature control frame using pool."""
1687
+ return await self._execute_with_pool(
1688
+ "add_gtol",
1689
+ lambda adapter: adapter.add_gtol(
1690
+ characteristic,
1691
+ tolerance,
1692
+ x_mm,
1693
+ y_mm,
1694
+ diameter_zone,
1695
+ material_condition,
1696
+ datums,
1697
+ attach_at_mm,
1698
+ dimension,
1699
+ ),
1700
+ )
1701
+
1702
+ async def add_datum_tag(
1703
+ self,
1704
+ label: str,
1705
+ attach_at_mm: tuple[float, float],
1706
+ x_mm: float,
1707
+ y_mm: float,
1708
+ ) -> AdapterResult[dict[str, Any]]:
1709
+ """Add a datum feature symbol using pool."""
1710
+ return await self._execute_with_pool(
1711
+ "add_datum_tag",
1712
+ lambda adapter: adapter.add_datum_tag(label, attach_at_mm, x_mm, y_mm),
1713
+ )
1714
+
1715
+ async def create_standard_drawing(
1716
+ self,
1717
+ model_path: str,
1718
+ output_dir: str | None = None,
1719
+ title: str | None = None,
1720
+ subtitle: str | None = None,
1721
+ drawing_number: str | None = None,
1722
+ author: str = "",
1723
+ revision: str = "A",
1724
+ company: str = "",
1725
+ drawn_date: str | None = None,
1726
+ notes: list[str] | None = None,
1727
+ include_isometric: bool = True,
1728
+ write_model_properties: bool = True,
1729
+ title_block_text_height_mm: float | None = None,
1730
+ include_bom: bool = False,
1731
+ ) -> AdapterResult[dict[str, Any]]:
1732
+ """Create a complete standard A3 drawing using pool."""
1733
+ return await self._execute_with_pool(
1734
+ "create_standard_drawing",
1735
+ lambda adapter: adapter.create_standard_drawing(
1736
+ model_path,
1737
+ output_dir,
1738
+ title,
1739
+ subtitle,
1740
+ drawing_number,
1741
+ author,
1742
+ revision,
1743
+ company,
1744
+ drawn_date,
1745
+ notes,
1746
+ include_isometric,
1747
+ write_model_properties,
1748
+ title_block_text_height_mm,
1749
+ include_bom,
1750
+ ),
1751
+ )
1752
+
1753
+
1754
+ class ConnectionPool:
1755
+ """Legacy alias class expected by tests.
1756
+
1757
+ Args:
1758
+ create_connection (Callable[[], object | Awaitable[object]]): Factory callable used
1759
+ to create a
1760
+ connection.
1761
+ max_size (int): Maximum number of items allowed in the pool. Defaults to 3.
1762
+ timeout (float): Maximum time to wait in seconds. Defaults to 30.0.
1763
+
1764
+ Attributes:
1765
+ _create_connection (Any): The create connection value.
1766
+ _max_size (Any): The max size value.
1767
+ _timeout (Any): The timeout value.
1768
+ """
1769
+
1770
+ def __init__(
1771
+ self,
1772
+ create_connection: Callable[[], object | Awaitable[object]],
1773
+ max_size: int = 3,
1774
+ timeout: float = 30.0,
1775
+ ) -> None:
1776
+ """Initialize the connection pool.
1777
+
1778
+ Args:
1779
+ create_connection (Callable[[], object | Awaitable[object]]): Factory callable used
1780
+ to create a
1781
+ connection.
1782
+ max_size (int): Maximum number of items allowed in the pool. Defaults to 3.
1783
+ timeout (float): Maximum time to wait in seconds. Defaults to 30.0.
1784
+
1785
+ Returns:
1786
+ None: None.
1787
+ """
1788
+ self._create_connection = create_connection
1789
+ self._max_size = max_size
1790
+ self._timeout = timeout
1791
+ self._available: list[object] = []
1792
+ self._in_use: set[int] = set()
1793
+ self._all_connections: list[object] = []
1794
+
1795
+ @property
1796
+ def size(self) -> int:
1797
+ """Provide size support for the connection pool.
1798
+
1799
+ Returns:
1800
+ int: The computed numeric result.
1801
+ """
1802
+ return len(self._all_connections)
1803
+
1804
+ @property
1805
+ def active_connections(self) -> int:
1806
+ """Provide active connections support for the connection pool.
1807
+
1808
+ Returns:
1809
+ int: The computed numeric result.
1810
+ """
1811
+ return len(self._in_use)
1812
+
1813
+ async def _new_connection(self) -> object:
1814
+ """Build internal new connection.
1815
+
1816
+ Returns:
1817
+ object: The result produced by the operation.
1818
+ """
1819
+ conn = self._create_connection()
1820
+ if asyncio.iscoroutine(conn):
1821
+ conn = await conn
1822
+ self._all_connections.append(conn)
1823
+ return conn
1824
+
1825
+ async def acquire(self) -> object:
1826
+ """Provide acquire support for the connection pool.
1827
+
1828
+ Returns:
1829
+ object: The result produced by the operation.
1830
+
1831
+ Raises:
1832
+ TimeoutError: No connection available within timeout.
1833
+ """
1834
+ if self._available:
1835
+ conn = self._available.pop()
1836
+ self._in_use.add(id(conn))
1837
+ return conn
1838
+
1839
+ if len(self._all_connections) < self._max_size:
1840
+ conn = await self._new_connection()
1841
+ self._in_use.add(id(conn))
1842
+ return conn
1843
+
1844
+ end_time = time.time() + self._timeout
1845
+ while time.time() < end_time:
1846
+ if self._available:
1847
+ conn = self._available.pop()
1848
+ self._in_use.add(id(conn))
1849
+ return conn
1850
+ await asyncio.sleep(0.01)
1851
+
1852
+ raise TimeoutError("No connection available within timeout")
1853
+
1854
+ async def release(self, conn: object) -> None:
1855
+ """Provide release support for the connection pool.
1856
+
1857
+ Args:
1858
+ conn (object): The conn value.
1859
+
1860
+ Returns:
1861
+ None: None.
1862
+ """
1863
+ conn_id = id(conn)
1864
+ if conn_id in self._in_use:
1865
+ self._in_use.remove(conn_id)
1866
+ self._available.append(conn)
1867
+
1868
+ async def cleanup(self) -> None:
1869
+ """Provide cleanup support for the connection pool.
1870
+
1871
+ Returns:
1872
+ None: None.
1873
+ """
1874
+ for conn in self._all_connections:
1875
+ close = getattr(conn, "close", None)
1876
+ if close is None:
1877
+ continue
1878
+ result = close()
1879
+ if asyncio.iscoroutine(result):
1880
+ await result
1881
+
1882
+ self._available.clear()
1883
+ self._in_use.clear()
1884
+ self._all_connections.clear()