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,17 @@
1
+ """Grouped SolidWorks mixins for the PyWin32 adapter."""
2
+
3
+ from .documentation import SolidWorksDocumentationMixin
4
+ from .drawing_standard import SolidWorksDrawingStandardMixin
5
+ from .features import SolidWorksFeaturesMixin
6
+ from .io import SolidWorksIOMixin
7
+ from .selection import SolidWorksSelectionMixin
8
+ from .sketch import SolidWorksSketchMixin
9
+
10
+ __all__ = [
11
+ "SolidWorksDocumentationMixin",
12
+ "SolidWorksDrawingStandardMixin",
13
+ "SolidWorksFeaturesMixin",
14
+ "SolidWorksIOMixin",
15
+ "SolidWorksSelectionMixin",
16
+ "SolidWorksSketchMixin",
17
+ ]
@@ -0,0 +1,180 @@
1
+ """Turn ``IModelDoc2.SaveBMP`` output into PNG/JPEG and read image sizes.
2
+
3
+ ``SaveBMP(path, width, height)`` is the only SolidWorks call that renders the
4
+ view at a caller-chosen pixel size; ``SaveAs3`` to ``.png`` always writes the
5
+ window's size. It only writes BMP, so a PNG is produced here with the
6
+ standard library (``zlib``) - Pillow is an optional extra and absent from the
7
+ server's environment. JPEG needs Pillow and reports ``ImportError`` without
8
+ it, so the caller can fall back.
9
+
10
+ ``SaveBMP`` keeps the window's framing, so an image whose aspect differs
11
+ from the window's crops the zoomed-to-fit model. The caller therefore
12
+ renders at the window's aspect and :func:`pad` extends the picture to the
13
+ requested size by repeating its edge pixels (the background).
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import struct
19
+ import zlib
20
+ from pathlib import Path
21
+
22
+
23
+ def read_bmp(path: str | Path) -> tuple[int, int, list[bytes]]:
24
+ """Read an uncompressed 24/32-bit BMP.
25
+
26
+ Returns:
27
+ tuple[int, int, list[bytes]]: Width, height and the RGB rows, top
28
+ row first.
29
+
30
+ Raises:
31
+ ValueError: When the file is not an uncompressed 24/32-bit BMP.
32
+ """
33
+ data = Path(path).read_bytes()
34
+ if len(data) < 54 or data[:2] != b"BM":
35
+ raise ValueError(f"{path} is not a BMP file")
36
+ offset = struct.unpack_from("<I", data, 10)[0]
37
+ width, height = struct.unpack_from("<ii", data, 18)
38
+ bits, compression = struct.unpack_from("<HI", data, 28)
39
+ # BI_RGB (0), or BI_BITFIELDS (3) with the standard BGRA masks at 32 bpp.
40
+ if bits not in (24, 32) or compression not in (0, 3) or width <= 0:
41
+ raise ValueError(
42
+ f"{path}: unsupported BMP ({bits} bpp, compression {compression})"
43
+ )
44
+ step = bits // 8
45
+ stride = (width * step + 3) & ~3
46
+ top_down = height < 0
47
+ height = abs(height)
48
+ rows = []
49
+ for index in range(height):
50
+ start = offset + index * stride
51
+ bgr = data[start : start + width * step]
52
+ rgb = bytearray(width * 3)
53
+ rgb[0::3] = bgr[2::step]
54
+ rgb[1::3] = bgr[1::step]
55
+ rgb[2::3] = bgr[0::step]
56
+ rows.append(bytes(rgb))
57
+ if not top_down:
58
+ rows.reverse()
59
+ return width, height, rows
60
+
61
+
62
+ def fit_aspect(width: int, height: int, aspect: float) -> tuple[int, int]:
63
+ """Largest ``aspect`` (width / height) size that fits in ``width`` x ``height``."""
64
+ if width / height > aspect:
65
+ return max(1, round(height * aspect)), height
66
+ return width, max(1, round(width / aspect))
67
+
68
+
69
+ def pad(
70
+ width: int, height: int, rows: list[bytes], target: tuple[int, int]
71
+ ) -> list[bytes]:
72
+ """Centre RGB ``rows`` in a ``target`` canvas, repeating the edge pixels.
73
+
74
+ Raises:
75
+ ValueError: When the image is larger than ``target``.
76
+ """
77
+ target_w, target_h = target
78
+ if width > target_w or height > target_h:
79
+ raise ValueError(f"{width}x{height} does not fit in {target_w}x{target_h}")
80
+ left = (target_w - width) // 2
81
+ right = target_w - width - left
82
+ widened = [row[:3] * left + row + row[-3:] * right for row in rows]
83
+ top = (target_h - height) // 2
84
+ bottom = target_h - height - top
85
+ return [widened[0]] * top + widened + [widened[-1]] * bottom
86
+
87
+
88
+ def write_bmp(path: str | Path, width: int, height: int, rows: list[bytes]) -> None:
89
+ """Write RGB rows (top first) as a bottom-up 24-bit BMP."""
90
+ stride = (width * 3 + 3) & ~3
91
+ body = bytearray()
92
+ for row in reversed(rows):
93
+ bgr = bytearray(width * 3)
94
+ bgr[0::3] = row[2::3]
95
+ bgr[1::3] = row[1::3]
96
+ bgr[2::3] = row[0::3]
97
+ body += bgr + b"\x00" * (stride - width * 3)
98
+ header = struct.pack(
99
+ "<2sIHHIIiiHHIIiiII",
100
+ *(b"BM", 54 + len(body), 0, 0, 54, 40, width, height, 1, 24, 0),
101
+ *(len(body), 2835, 2835, 0, 0),
102
+ )
103
+ Path(path).write_bytes(header + bytes(body))
104
+
105
+
106
+ def write_png(path: str | Path, width: int, height: int, rows: list[bytes]) -> None:
107
+ """Write 8-bit RGB rows (top first) as a PNG."""
108
+
109
+ def chunk(kind: bytes, body: bytes) -> bytes:
110
+ return (
111
+ struct.pack(">I", len(body))
112
+ + kind
113
+ + body
114
+ + struct.pack(">I", zlib.crc32(kind + body) & 0xFFFFFFFF)
115
+ )
116
+
117
+ raw = b"".join(b"\x00" + row for row in rows)
118
+ Path(path).write_bytes(
119
+ b"\x89PNG\r\n\x1a\n"
120
+ + chunk(b"IHDR", struct.pack(">IIBBBBB", width, height, 8, 2, 0, 0, 0))
121
+ + chunk(b"IDAT", zlib.compress(raw, 6))
122
+ + chunk(b"IEND", b"")
123
+ )
124
+
125
+
126
+ def convert_bmp(
127
+ source: str | Path, target: str | Path, size: tuple[int, int] | None = None
128
+ ) -> None:
129
+ """Convert a BMP to the format named by ``target``'s extension.
130
+
131
+ Args:
132
+ source: The BMP ``SaveBMP`` wrote.
133
+ target: Output path; ``.png``, ``.bmp``, ``.jpg`` or ``.jpeg``.
134
+ size: Pad the picture to this ``(width, height)`` (see :func:`pad`).
135
+
136
+ Raises:
137
+ ImportError: For JPEG when Pillow is not installed.
138
+ ValueError: For any other extension, a BMP that :func:`read_bmp`
139
+ cannot read, or one larger than ``size``.
140
+ """
141
+ suffix = Path(target).suffix.lower()
142
+ if suffix not in (".png", ".bmp", ".jpg", ".jpeg"):
143
+ raise ValueError(f"Cannot convert a BMP to {suffix!r}")
144
+ width, height, rows = read_bmp(source)
145
+ if size is not None:
146
+ rows = pad(width, height, rows, size)
147
+ width, height = size
148
+ if suffix == ".png":
149
+ write_png(target, width, height, rows)
150
+ elif suffix == ".bmp":
151
+ write_bmp(target, width, height, rows)
152
+ else:
153
+ from PIL import Image
154
+
155
+ image = Image.frombytes("RGB", (width, height), b"".join(rows))
156
+ image.save(target, "JPEG", quality=92)
157
+
158
+
159
+ def image_size(path: str | Path) -> tuple[int, int] | None:
160
+ """Return ``(width, height)`` of a PNG, BMP or JPEG, or ``None``."""
161
+ try:
162
+ data = Path(path).read_bytes()
163
+ except OSError:
164
+ return None
165
+ if data[:8] == b"\x89PNG\r\n\x1a\n" and len(data) >= 24:
166
+ return struct.unpack_from(">II", data, 16)
167
+ if data[:2] == b"BM" and len(data) >= 26:
168
+ width, height = struct.unpack_from("<ii", data, 18)
169
+ return width, abs(height)
170
+ if data[:2] == b"\xff\xd8":
171
+ index = 2
172
+ while index + 9 <= len(data) and data[index] == 0xFF:
173
+ marker = data[index + 1]
174
+ length = struct.unpack_from(">H", data, index + 2)[0]
175
+ # SOF0..SOF15 carry the frame size; C4/C8/CC are not frames.
176
+ if 0xC0 <= marker <= 0xCF and marker not in (0xC4, 0xC8, 0xCC):
177
+ height, width = struct.unpack_from(">HH", data, index + 5)
178
+ return width, height
179
+ index += 2 + length
180
+ return None
@@ -0,0 +1,56 @@
1
+ """Small COM helpers shared by the selection / face / rebuild modules.
2
+
3
+ One copy of each, so error-handling and flagging behaviour cannot drift
4
+ between modules.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any
10
+
11
+ from .. import sw_type_info as _sw_type_info
12
+
13
+
14
+ def attempt(adapter: Any, fn: Any, default: Any = None) -> Any:
15
+ """Run ``fn`` through the adapter's ``_attempt`` (exceptions -> default)."""
16
+ return adapter._attempt(fn, default=default)
17
+
18
+
19
+ def flag(adapter: Any, obj: Any, *names: str) -> None:
20
+ """Flag just ``names`` as methods on ``obj`` (no-op for ``None``/fakes).
21
+
22
+ Flagging a whole interface costs ~27 ms per fresh dispatch (see
23
+ ``_WALK_MEMBERS`` in pywin32_adapter); SolidWorks hands back a fresh
24
+ dispatch on most calls, so flag only what is about to be read.
25
+ """
26
+ attempt(adapter, lambda: _sw_type_info.flag_members(obj, *names), 0)
27
+
28
+
29
+ def as_list(value: Any) -> list[Any]:
30
+ """Normalise a COM array/scalar/None return into a list."""
31
+ if value is None:
32
+ return []
33
+ if isinstance(value, (list, tuple)):
34
+ return list(value)
35
+ return [value]
36
+
37
+
38
+ def selection_count(adapter: Any, model: Any) -> int | None:
39
+ """Number of entities currently selected in ``model``, or None."""
40
+ sel_mgr = attempt(adapter, lambda: model.SelectionManager)
41
+ if sel_mgr is None:
42
+ return None
43
+ flag(adapter, sel_mgr, "GetSelectedObjectCount2")
44
+ count = attempt(adapter, lambda: sel_mgr.GetSelectedObjectCount2(-1))
45
+ return int(count) if isinstance(count, (int, float)) else None
46
+
47
+
48
+ def strip_op_prefix(error: str | None, operation_name: str) -> str | None:
49
+ """Drop ``_handle_com_operation``'s generic ``"Error in <op>: "`` prefix.
50
+
51
+ Expected failures (not found, nothing to select, rebuild errors) then read
52
+ as plain sentences for the LLM caller.
53
+ """
54
+ if not error:
55
+ return error
56
+ return error.removeprefix(f"Error in {operation_name}: ")