sldkit 0.2.0__cp310-abi3-win_amd64.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 (33) hide show
  1. sldkit/__init__.py +269 -0
  2. sldkit/__main__.py +3 -0
  3. sldkit/_core.pyd +0 -0
  4. sldkit/_core.pyi +35 -0
  5. sldkit/api.py +309 -0
  6. sldkit/cli.py +183 -0
  7. sldkit/errors.py +45 -0
  8. sldkit/model.py +3079 -0
  9. sldkit/py.typed +1 -0
  10. sldkit/viewer/__init__.py +8 -0
  11. sldkit/viewer/_assets/LICENSE.txt +254 -0
  12. sldkit/viewer/_assets/three-LICENSE.txt +21 -0
  13. sldkit/viewer/_assets/viewer.css +4 -0
  14. sldkit/viewer/_assets/viewer.html +73 -0
  15. sldkit/viewer/_assets/viewer.js +4100 -0
  16. sldkit/viewer/_html.py +333 -0
  17. sldkit-0.2.0.dist-info/METADATA +229 -0
  18. sldkit-0.2.0.dist-info/RECORD +33 -0
  19. sldkit-0.2.0.dist-info/WHEEL +4 -0
  20. sldkit-0.2.0.dist-info/entry_points.txt +2 -0
  21. sldkit-0.2.0.dist-info/licenses/COMMERCIAL-LICENSE.md +83 -0
  22. sldkit-0.2.0.dist-info/licenses/LICENSE +38 -0
  23. sldkit-0.2.0.dist-info/licenses/LICENSES/Apache-2.0.txt +201 -0
  24. sldkit-0.2.0.dist-info/licenses/LICENSES/PolyForm-Noncommercial-1.0.0.md +73 -0
  25. sldkit-0.2.0.dist-info/licenses/LICENSES/README.md +37 -0
  26. sldkit-0.2.0.dist-info/licenses/LICENSES/parasolid-core-MIT.txt +21 -0
  27. sldkit-0.2.0.dist-info/licenses/LICENSES/parasolid-core-PARTIAL_READERS.md +90 -0
  28. sldkit-0.2.0.dist-info/licenses/LICENSES/rust-dependencies.json +2100 -0
  29. sldkit-0.2.0.dist-info/licenses/LICENSES/rust-dependencies.txt +3967 -0
  30. sldkit-0.2.0.dist-info/licenses/LICENSES/sldkit-legacy-MIT.txt +21 -0
  31. sldkit-0.2.0.dist-info/licenses/LICENSES/three-MIT.txt +21 -0
  32. sldkit-0.2.0.dist-info/licenses/THIRD_PARTY_NOTICES.md +70 -0
  33. sldkit-0.2.0.dist-info/sboms/sldkit-python.cyclonedx.json +2554 -0
sldkit/__init__.py ADDED
@@ -0,0 +1,269 @@
1
+ from .api import (
2
+ decode_drawing_structure_bytes,
3
+ decode_drawing_structure_file,
4
+ decode_geometry_bytes,
5
+ decode_geometry_file,
6
+ extract_bytes,
7
+ extract_file,
8
+ extract_resource_bytes,
9
+ extract_resource_file,
10
+ inspect_bytes,
11
+ inspect_file,
12
+ parse_bytes,
13
+ parse_file,
14
+ probe_bytes,
15
+ probe_file,
16
+ scan_project,
17
+ )
18
+ from .errors import DrawingStructureError, GeometryError, ParseError, SldkitError
19
+ from .model import (
20
+ AssemblyComponent,
21
+ BinaryResource,
22
+ BinaryResourceKind,
23
+ ByteRange,
24
+ ChecksumStatus,
25
+ CompressionMethod,
26
+ Configuration,
27
+ ContainerInventory,
28
+ CoverageReport,
29
+ CustomProperty,
30
+ Diagnostic,
31
+ DiagnosticKind,
32
+ DiagnosticSeverity,
33
+ DocumentKind,
34
+ DocumentReference,
35
+ DrawingBytePartitionStatus,
36
+ DrawingCarrier,
37
+ DrawingCarrierRole,
38
+ DrawingRecord,
39
+ DrawingRecordClass,
40
+ DrawingRecordSource,
41
+ DrawingSheet,
42
+ DrawingStructureCoverage,
43
+ DrawingStructureDocument,
44
+ DrawingStructureResult,
45
+ DrawingStructureSheet,
46
+ DrawingStructureStatus,
47
+ DrawingStructureView,
48
+ DrawingView,
49
+ Envelope,
50
+ ExtractionMode,
51
+ ExtractionResult,
52
+ ExtractionStatus,
53
+ GeometryBody,
54
+ GeometryByteClassification,
55
+ GeometryByteCoverage,
56
+ GeometryByteDomain,
57
+ GeometryByteOffsetBasis,
58
+ GeometryBytePartitionStatus,
59
+ GeometryByteRange,
60
+ GeometryByteStorage,
61
+ GeometryCarrier,
62
+ GeometryCarrierDomain,
63
+ GeometryCoedge,
64
+ GeometryConfigurationState,
65
+ GeometryConstruction,
66
+ GeometryConstructionDomain,
67
+ GeometryDecodedSpan,
68
+ GeometryDocument,
69
+ GeometryEdge,
70
+ GeometryEntityProvenance,
71
+ GeometryExactness,
72
+ GeometryFace,
73
+ GeometryFidelityReport,
74
+ GeometryFinding,
75
+ GeometryLoop,
76
+ GeometryLoss,
77
+ GeometryModel,
78
+ GeometryPcurveState,
79
+ GeometryPcurveUse,
80
+ GeometryPoint,
81
+ GeometryRawRecord,
82
+ GeometryRegion,
83
+ GeometryResult,
84
+ GeometryShell,
85
+ GeometrySourceObject,
86
+ GeometryStatus,
87
+ GeometryStreamCandidate,
88
+ GeometryStreamRole,
89
+ GeometryStreamSelection,
90
+ GeometryTessellation,
91
+ GeometryTessellationChannel,
92
+ GeometryTessellationTextureAssignment,
93
+ GeometryTessellationTriangleGroup,
94
+ GeometryTopologyMetrics,
95
+ GeometryVertex,
96
+ GeometryVertexUse,
97
+ InventoryEntry,
98
+ InventoryEntryKind,
99
+ InventoryEntryState,
100
+ InventoryResult,
101
+ InventoryStatus,
102
+ LimitProfile,
103
+ MassProperties,
104
+ ParseResult,
105
+ ParseStatus,
106
+ ProbeConfidence,
107
+ ProbeEvidence,
108
+ ProbeResult,
109
+ ProbeStatus,
110
+ ProjectCompatibilityReport,
111
+ ProjectConfigurationIdentity,
112
+ ProjectEdge,
113
+ ProjectNode,
114
+ ProjectScanResult,
115
+ ProjectScanStatus,
116
+ PropertyKind,
117
+ PropertyScope,
118
+ PropertyValueState,
119
+ RecordOffsetBasis,
120
+ ReferenceKind,
121
+ ReferenceResolutionBasis,
122
+ ReferenceResolutionStatus,
123
+ ReferenceTraversalStatus,
124
+ SemanticCoverage,
125
+ SourceDocument,
126
+ SourcedValue,
127
+ SourceInfo,
128
+ SourceInputKind,
129
+ StreamExtraction,
130
+ UnknownRecord,
131
+ ValueOrigin,
132
+ )
133
+
134
+ __version__ = "0.2.0"
135
+
136
+ __all__ = [
137
+ "AssemblyComponent",
138
+ "BinaryResource",
139
+ "BinaryResourceKind",
140
+ "ByteRange",
141
+ "ChecksumStatus",
142
+ "CompressionMethod",
143
+ "Configuration",
144
+ "ContainerInventory",
145
+ "CoverageReport",
146
+ "CustomProperty",
147
+ "Diagnostic",
148
+ "DiagnosticKind",
149
+ "DiagnosticSeverity",
150
+ "DocumentKind",
151
+ "DocumentReference",
152
+ "DrawingBytePartitionStatus",
153
+ "DrawingCarrier",
154
+ "DrawingCarrierRole",
155
+ "DrawingRecord",
156
+ "DrawingRecordClass",
157
+ "DrawingRecordSource",
158
+ "DrawingSheet",
159
+ "DrawingStructureCoverage",
160
+ "DrawingStructureDocument",
161
+ "DrawingStructureError",
162
+ "DrawingStructureResult",
163
+ "DrawingStructureSheet",
164
+ "DrawingStructureStatus",
165
+ "DrawingStructureView",
166
+ "DrawingView",
167
+ "Envelope",
168
+ "ExtractionMode",
169
+ "ExtractionResult",
170
+ "ExtractionStatus",
171
+ "GeometryBody",
172
+ "GeometryByteCoverage",
173
+ "GeometryByteClassification",
174
+ "GeometryByteRange",
175
+ "GeometryDecodedSpan",
176
+ "GeometryByteDomain",
177
+ "GeometryByteOffsetBasis",
178
+ "GeometryBytePartitionStatus",
179
+ "GeometryByteStorage",
180
+ "GeometryCarrier",
181
+ "GeometryCarrierDomain",
182
+ "GeometryCoedge",
183
+ "GeometryConfigurationState",
184
+ "GeometryConstruction",
185
+ "GeometryConstructionDomain",
186
+ "GeometryDocument",
187
+ "GeometryEdge",
188
+ "GeometryEntityProvenance",
189
+ "GeometryError",
190
+ "GeometryExactness",
191
+ "GeometryFace",
192
+ "GeometryFidelityReport",
193
+ "GeometryFinding",
194
+ "GeometryLoop",
195
+ "GeometryLoss",
196
+ "GeometryModel",
197
+ "GeometryPcurveState",
198
+ "GeometryPcurveUse",
199
+ "GeometryPoint",
200
+ "GeometryRawRecord",
201
+ "GeometryRegion",
202
+ "GeometryResult",
203
+ "GeometryShell",
204
+ "GeometrySourceObject",
205
+ "GeometryStatus",
206
+ "GeometryStreamCandidate",
207
+ "GeometryStreamRole",
208
+ "GeometryStreamSelection",
209
+ "GeometryTessellation",
210
+ "GeometryTessellationChannel",
211
+ "GeometryTessellationTextureAssignment",
212
+ "GeometryTessellationTriangleGroup",
213
+ "GeometryTopologyMetrics",
214
+ "GeometryVertex",
215
+ "GeometryVertexUse",
216
+ "InventoryEntry",
217
+ "InventoryEntryKind",
218
+ "InventoryEntryState",
219
+ "InventoryResult",
220
+ "InventoryStatus",
221
+ "LimitProfile",
222
+ "MassProperties",
223
+ "ParseError",
224
+ "ParseResult",
225
+ "ParseStatus",
226
+ "ProbeConfidence",
227
+ "ProbeEvidence",
228
+ "ProbeResult",
229
+ "ProbeStatus",
230
+ "ProjectCompatibilityReport",
231
+ "ProjectConfigurationIdentity",
232
+ "ProjectEdge",
233
+ "ProjectNode",
234
+ "ProjectScanResult",
235
+ "ProjectScanStatus",
236
+ "PropertyKind",
237
+ "PropertyScope",
238
+ "PropertyValueState",
239
+ "RecordOffsetBasis",
240
+ "ReferenceKind",
241
+ "ReferenceResolutionBasis",
242
+ "ReferenceResolutionStatus",
243
+ "ReferenceTraversalStatus",
244
+ "SemanticCoverage",
245
+ "SldkitError",
246
+ "SourceDocument",
247
+ "SourceInfo",
248
+ "SourceInputKind",
249
+ "StreamExtraction",
250
+ "SourcedValue",
251
+ "UnknownRecord",
252
+ "ValueOrigin",
253
+ "__version__",
254
+ "decode_drawing_structure_bytes",
255
+ "decode_drawing_structure_file",
256
+ "decode_geometry_bytes",
257
+ "decode_geometry_file",
258
+ "extract_bytes",
259
+ "extract_file",
260
+ "extract_resource_bytes",
261
+ "extract_resource_file",
262
+ "inspect_bytes",
263
+ "inspect_file",
264
+ "parse_bytes",
265
+ "parse_file",
266
+ "probe_bytes",
267
+ "probe_file",
268
+ "scan_project",
269
+ ]
sldkit/__main__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())
sldkit/_core.pyd ADDED
Binary file
sldkit/_core.pyi ADDED
@@ -0,0 +1,35 @@
1
+ def probe_bytes_json(data: bytes, profile: str) -> str: ...
2
+ def probe_file_json(path: str, profile: str) -> str: ...
3
+ def inspect_bytes_json(data: bytes, filename: str | None, profile: str) -> str: ...
4
+ def inspect_file_json(path: str, profile: str) -> str: ...
5
+ def parse_bytes_json(data: bytes, filename: str | None, profile: str) -> str: ...
6
+ def parse_file_json(path: str, profile: str) -> str: ...
7
+ def decode_geometry_bytes_json(
8
+ data: bytes, filename: str | None, profile: str
9
+ ) -> str: ...
10
+ def decode_geometry_file_json(path: str, profile: str) -> str: ...
11
+ def decode_drawing_structure_bytes_json(
12
+ data: bytes, filename: str | None, profile: str
13
+ ) -> str: ...
14
+ def decode_drawing_structure_file_json(path: str, profile: str) -> str: ...
15
+ def scan_project_json(
16
+ path: str,
17
+ project_root: str | None,
18
+ configuration: str | None,
19
+ search_directories: list[str],
20
+ windows_prefix_mappings: list[tuple[str, str]],
21
+ follow_suppressed: bool,
22
+ profile: str,
23
+ ) -> str: ...
24
+ def extract_bytes_result(
25
+ data: bytes, entry_id: str, mode: str, profile: str
26
+ ) -> tuple[str, bytes | None]: ...
27
+ def extract_file_result(
28
+ path: str, entry_id: str, mode: str, profile: str
29
+ ) -> tuple[str, bytes | None]: ...
30
+ def extract_resource_bytes_result(
31
+ data: bytes, resource_json: str, profile: str
32
+ ) -> tuple[str, bytes | None]: ...
33
+ def extract_resource_file_result(
34
+ path: str, resource_json: str, profile: str
35
+ ) -> tuple[str, bytes | None]: ...
sldkit/api.py ADDED
@@ -0,0 +1,309 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ from collections.abc import Iterable, Mapping
6
+ from os import PathLike
7
+ from typing import Any
8
+
9
+ from . import _core
10
+ from .errors import DrawingStructureError, GeometryError, ParseError
11
+ from .model import (
12
+ BinaryResource,
13
+ DrawingStructureResult,
14
+ DrawingStructureStatus,
15
+ ExtractionMode,
16
+ ExtractionResult,
17
+ GeometryResult,
18
+ GeometryStatus,
19
+ InventoryResult,
20
+ LimitProfile,
21
+ ParseResult,
22
+ ParseStatus,
23
+ ProbeResult,
24
+ ProjectScanResult,
25
+ StreamExtraction,
26
+ )
27
+
28
+ BytesLike = bytes | bytearray | memoryview
29
+ PathType = str | PathLike[str]
30
+ WindowsPrefixMappings = Mapping[str, PathType] | Iterable[tuple[str, PathType]]
31
+
32
+
33
+ def probe_bytes(
34
+ data: BytesLike,
35
+ *,
36
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
37
+ ) -> ProbeResult:
38
+ """Classify a bounded byte input by content without semantic parsing."""
39
+ payload = _load_json(_core.probe_bytes_json(bytes(data), _profile_name(profile)))
40
+ return ProbeResult.from_dict(payload)
41
+
42
+
43
+ def probe_file(
44
+ path: PathType,
45
+ *,
46
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
47
+ ) -> ProbeResult:
48
+ """Read a file under a resource limit and classify its envelope."""
49
+ payload = _load_json(
50
+ _core.probe_file_json(os.fsdecode(os.fspath(path)), _profile_name(profile))
51
+ )
52
+ return ProbeResult.from_dict(payload)
53
+
54
+
55
+ def inspect_bytes(
56
+ data: BytesLike,
57
+ *,
58
+ filename: str | None = None,
59
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
60
+ ) -> InventoryResult:
61
+ """Return a bounded, deterministic inventory without document semantics."""
62
+ payload = _load_json(
63
+ _core.inspect_bytes_json(bytes(data), filename, _profile_name(profile))
64
+ )
65
+ return InventoryResult.from_dict(payload)
66
+
67
+
68
+ def inspect_file(
69
+ path: PathType,
70
+ *,
71
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
72
+ ) -> InventoryResult:
73
+ """Read a file under a resource limit and inventory its outer container."""
74
+ payload = _load_json(
75
+ _core.inspect_file_json(os.fsdecode(os.fspath(path)), _profile_name(profile))
76
+ )
77
+ return InventoryResult.from_dict(payload)
78
+
79
+
80
+ def extract_bytes(
81
+ data: BytesLike,
82
+ entry_id: str,
83
+ *,
84
+ mode: str | ExtractionMode = ExtractionMode.DECODED,
85
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
86
+ ) -> StreamExtraction:
87
+ """Extract one validated entry representation without filesystem expansion."""
88
+ metadata, payload = _core.extract_bytes_result(
89
+ bytes(data), entry_id, _mode_name(mode), _profile_name(profile)
90
+ )
91
+ return StreamExtraction(
92
+ result=ExtractionResult.from_dict(_load_json(metadata)), data=payload
93
+ )
94
+
95
+
96
+ def extract_file(
97
+ path: PathType,
98
+ entry_id: str,
99
+ *,
100
+ mode: str | ExtractionMode = ExtractionMode.DECODED,
101
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
102
+ ) -> StreamExtraction:
103
+ """Extract one validated entry from a bounded source path."""
104
+ metadata, payload = _core.extract_file_result(
105
+ os.fsdecode(os.fspath(path)),
106
+ entry_id,
107
+ _mode_name(mode),
108
+ _profile_name(profile),
109
+ )
110
+ return StreamExtraction(
111
+ result=ExtractionResult.from_dict(_load_json(metadata)), data=payload
112
+ )
113
+
114
+
115
+ def extract_resource_bytes(
116
+ data: BytesLike,
117
+ resource: BinaryResource,
118
+ *,
119
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
120
+ ) -> StreamExtraction:
121
+ """Extract and revalidate the exact bytes described by a binary resource."""
122
+ metadata, payload = _core.extract_resource_bytes_result(
123
+ bytes(data),
124
+ json.dumps(resource.to_dict(), separators=(",", ":"), sort_keys=True),
125
+ _profile_name(profile),
126
+ )
127
+ return StreamExtraction(
128
+ result=ExtractionResult.from_dict(_load_json(metadata)), data=payload
129
+ )
130
+
131
+
132
+ def extract_resource_file(
133
+ path: PathType,
134
+ resource: BinaryResource,
135
+ *,
136
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
137
+ ) -> StreamExtraction:
138
+ """Read a bounded file and extract one exact binary resource from it."""
139
+ metadata, payload = _core.extract_resource_file_result(
140
+ os.fsdecode(os.fspath(path)),
141
+ json.dumps(resource.to_dict(), separators=(",", ":"), sort_keys=True),
142
+ _profile_name(profile),
143
+ )
144
+ return StreamExtraction(
145
+ result=ExtractionResult.from_dict(_load_json(metadata)), data=payload
146
+ )
147
+
148
+
149
+ def parse_bytes(
150
+ data: BytesLike,
151
+ *,
152
+ filename: str | None = None,
153
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
154
+ strict: bool = False,
155
+ ) -> ParseResult:
156
+ """Parse supported facts while retaining partial or malformed results."""
157
+ payload = _load_json(
158
+ _core.parse_bytes_json(bytes(data), filename, _profile_name(profile))
159
+ )
160
+ return _apply_strict(ParseResult.from_dict(payload), strict)
161
+
162
+
163
+ def parse_file(
164
+ path: PathType,
165
+ *,
166
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
167
+ strict: bool = False,
168
+ ) -> ParseResult:
169
+ """Parse a path and retain its exact source identity and diagnostics."""
170
+ payload = _load_json(
171
+ _core.parse_file_json(os.fsdecode(os.fspath(path)), _profile_name(profile))
172
+ )
173
+ return _apply_strict(ParseResult.from_dict(payload), strict)
174
+
175
+
176
+ def decode_geometry_bytes(
177
+ data: BytesLike,
178
+ *,
179
+ filename: str | None = None,
180
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
181
+ strict: bool = False,
182
+ ) -> GeometryResult:
183
+ """Decode modern part geometry into the source-oriented geometry model."""
184
+ payload = _load_json(
185
+ _core.decode_geometry_bytes_json(bytes(data), filename, _profile_name(profile))
186
+ )
187
+ return _apply_geometry_strict(GeometryResult.from_dict(payload), strict)
188
+
189
+
190
+ def decode_geometry_file(
191
+ path: PathType,
192
+ *,
193
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
194
+ strict: bool = False,
195
+ ) -> GeometryResult:
196
+ """Decode modern part geometry while retaining provenance and loss details."""
197
+ payload = _load_json(
198
+ _core.decode_geometry_file_json(
199
+ os.fsdecode(os.fspath(path)), _profile_name(profile)
200
+ )
201
+ )
202
+ return _apply_geometry_strict(GeometryResult.from_dict(payload), strict)
203
+
204
+
205
+ def decode_drawing_structure_bytes(
206
+ data: BytesLike,
207
+ *,
208
+ filename: str | None = None,
209
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
210
+ strict: bool = False,
211
+ ) -> DrawingStructureResult:
212
+ """Inventory source-native records from a modern Drawing."""
213
+ payload = _load_json(
214
+ _core.decode_drawing_structure_bytes_json(
215
+ bytes(data), filename, _profile_name(profile)
216
+ )
217
+ )
218
+ return _apply_drawing_structure_strict(
219
+ DrawingStructureResult.from_dict(payload), strict
220
+ )
221
+
222
+
223
+ def decode_drawing_structure_file(
224
+ path: PathType,
225
+ *,
226
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
227
+ strict: bool = False,
228
+ ) -> DrawingStructureResult:
229
+ """Inventory Drawing records while retaining exact source ranges and carriers."""
230
+ payload = _load_json(
231
+ _core.decode_drawing_structure_file_json(
232
+ os.fsdecode(os.fspath(path)), _profile_name(profile)
233
+ )
234
+ )
235
+ return _apply_drawing_structure_strict(
236
+ DrawingStructureResult.from_dict(payload), strict
237
+ )
238
+
239
+
240
+ def scan_project(
241
+ path: PathType,
242
+ *,
243
+ project_root: PathType | None = None,
244
+ configuration: str | None = None,
245
+ search_directories: Iterable[PathType] = (),
246
+ windows_prefix_mappings: WindowsPrefixMappings | None = None,
247
+ follow_suppressed: bool = False,
248
+ profile: str | LimitProfile = LimitProfile.DESKTOP,
249
+ ) -> ProjectScanResult:
250
+ """Resolve a bounded local document graph without changing stored paths."""
251
+ mappings = (
252
+ ()
253
+ if windows_prefix_mappings is None
254
+ else (
255
+ windows_prefix_mappings.items()
256
+ if isinstance(windows_prefix_mappings, Mapping)
257
+ else windows_prefix_mappings
258
+ )
259
+ )
260
+ payload = _load_json(
261
+ _core.scan_project_json(
262
+ os.fsdecode(os.fspath(path)),
263
+ (None if project_root is None else os.fsdecode(os.fspath(project_root))),
264
+ configuration,
265
+ [os.fsdecode(os.fspath(item)) for item in search_directories],
266
+ [
267
+ (str(prefix), os.fsdecode(os.fspath(target)))
268
+ for prefix, target in mappings
269
+ ],
270
+ follow_suppressed,
271
+ _profile_name(profile),
272
+ )
273
+ )
274
+ return ProjectScanResult.from_dict(payload)
275
+
276
+
277
+ def _load_json(value: str) -> Mapping[str, Any]:
278
+ decoded = json.loads(value)
279
+ if not isinstance(decoded, dict):
280
+ raise RuntimeError("native parser returned a non-object JSON result")
281
+ return decoded
282
+
283
+
284
+ def _profile_name(profile: str | LimitProfile) -> str:
285
+ return profile.value if isinstance(profile, LimitProfile) else profile
286
+
287
+
288
+ def _mode_name(mode: str | ExtractionMode) -> str:
289
+ return mode.value if isinstance(mode, ExtractionMode) else mode
290
+
291
+
292
+ def _apply_strict(result: ParseResult, strict: bool) -> ParseResult:
293
+ if strict and result.status is not ParseStatus.PARSED:
294
+ raise ParseError(result)
295
+ return result
296
+
297
+
298
+ def _apply_geometry_strict(result: GeometryResult, strict: bool) -> GeometryResult:
299
+ if strict and result.status is not GeometryStatus.DECODED:
300
+ raise GeometryError(result)
301
+ return result
302
+
303
+
304
+ def _apply_drawing_structure_strict(
305
+ result: DrawingStructureResult, strict: bool
306
+ ) -> DrawingStructureResult:
307
+ if strict and result.status is not DrawingStructureStatus.INVENTORIED:
308
+ raise DrawingStructureError(result)
309
+ return result