windowsml 1.8.2192__py3-none-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.
- windowsml-1.8.2192.data/purelib/windowsml/__init__.py +973 -0
- windowsml-1.8.2192.data/purelib/windowsml/_bindings.py +502 -0
- windowsml-1.8.2192.data/purelib/windowsml/lib/Microsoft.Windows.AI.MachineLearning.dll +0 -0
- windowsml-1.8.2192.dist-info/METADATA +183 -0
- windowsml-1.8.2192.dist-info/RECORD +7 -0
- windowsml-1.8.2192.dist-info/WHEEL +5 -0
- windowsml-1.8.2192.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,973 @@
|
|
|
1
|
+
# Copyright (C) Microsoft Corporation. All rights reserved.
|
|
2
|
+
"""Python bindings for the Windows AI Machine Learning API."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import ctypes
|
|
7
|
+
from typing import Callable, Optional
|
|
8
|
+
|
|
9
|
+
from windowsml._bindings import (
|
|
10
|
+
AsyncBlock,
|
|
11
|
+
AsyncCompletionCallback,
|
|
12
|
+
AsyncProgressCallback,
|
|
13
|
+
CatalogModelInfoEnumCallback,
|
|
14
|
+
CatalogModelInfoHandle,
|
|
15
|
+
CatalogModelInstanceHandle,
|
|
16
|
+
CatalogModelInstanceResult,
|
|
17
|
+
CatalogModelInstanceStatus,
|
|
18
|
+
CatalogModelStatus,
|
|
19
|
+
EpCatalogHandle,
|
|
20
|
+
EpCertification,
|
|
21
|
+
EpEnumCallback,
|
|
22
|
+
EpReadyState,
|
|
23
|
+
ModelCatalogHandle,
|
|
24
|
+
ModelCatalogSourceHandle,
|
|
25
|
+
StringEnumCallback,
|
|
26
|
+
WinMLAsyncCancel,
|
|
27
|
+
WinMLAsyncClose,
|
|
28
|
+
WinMLAsyncGetStatus,
|
|
29
|
+
WinMLCatalogModelInfoEnumExecutionProviders,
|
|
30
|
+
WinMLCatalogModelInfoGetId,
|
|
31
|
+
WinMLCatalogModelInfoGetIdSize,
|
|
32
|
+
WinMLCatalogModelInfoGetInstanceAsync,
|
|
33
|
+
WinMLCatalogModelInfoGetInstanceResult,
|
|
34
|
+
WinMLCatalogModelInfoGetInstanceWithHeadersAsync,
|
|
35
|
+
WinMLCatalogModelInfoGetLicense,
|
|
36
|
+
WinMLCatalogModelInfoGetLicenseSize,
|
|
37
|
+
WinMLCatalogModelInfoGetLicenseText,
|
|
38
|
+
WinMLCatalogModelInfoGetLicenseTextSize,
|
|
39
|
+
WinMLCatalogModelInfoGetLicenseUri,
|
|
40
|
+
WinMLCatalogModelInfoGetLicenseUriSize,
|
|
41
|
+
WinMLCatalogModelInfoGetModelSizeInBytes,
|
|
42
|
+
WinMLCatalogModelInfoGetName,
|
|
43
|
+
WinMLCatalogModelInfoGetNameSize,
|
|
44
|
+
WinMLCatalogModelInfoGetPublisher,
|
|
45
|
+
WinMLCatalogModelInfoGetPublisherSize,
|
|
46
|
+
WinMLCatalogModelInfoGetSourceId,
|
|
47
|
+
WinMLCatalogModelInfoGetSourceIdSize,
|
|
48
|
+
WinMLCatalogModelInfoGetStatus,
|
|
49
|
+
WinMLCatalogModelInfoGetUri,
|
|
50
|
+
WinMLCatalogModelInfoGetUriSize,
|
|
51
|
+
WinMLCatalogModelInfoGetVersion,
|
|
52
|
+
WinMLCatalogModelInfoGetVersionSize,
|
|
53
|
+
WinMLCatalogModelInfoRelease,
|
|
54
|
+
WinMLCatalogModelInstanceClose,
|
|
55
|
+
WinMLCatalogModelInstanceEnumModelPaths,
|
|
56
|
+
WinMLCatalogModelInstanceGetModelInfo,
|
|
57
|
+
WinMLCatalogModelInstanceRelease,
|
|
58
|
+
WinMLEpCatalogCreate,
|
|
59
|
+
WinMLEpCatalogEnumProviders,
|
|
60
|
+
WinMLEpCatalogRelease,
|
|
61
|
+
WinMLEpEnsureReady,
|
|
62
|
+
WinMLEpEnsureReadyAsync,
|
|
63
|
+
WinMLEpGetCertification,
|
|
64
|
+
WinMLEpGetLibraryPath,
|
|
65
|
+
WinMLEpGetLibraryPathSize,
|
|
66
|
+
WinMLEpGetName,
|
|
67
|
+
WinMLEpGetNameSize,
|
|
68
|
+
WinMLEpGetPackageFamilyName,
|
|
69
|
+
WinMLEpGetPackageFamilyNameSize,
|
|
70
|
+
WinMLEpGetPackageRootPath,
|
|
71
|
+
WinMLEpGetPackageRootPathSize,
|
|
72
|
+
WinMLEpGetReadyState,
|
|
73
|
+
WinMLEpGetVersion,
|
|
74
|
+
WinMLEpGetVersionSize,
|
|
75
|
+
WinMLModelCatalogCreate,
|
|
76
|
+
WinMLModelCatalogEnumExecutionProviders,
|
|
77
|
+
WinMLModelCatalogFindAllModels,
|
|
78
|
+
WinMLModelCatalogFindAllModelsAsync,
|
|
79
|
+
WinMLModelCatalogFindAllModelsGetResult,
|
|
80
|
+
WinMLModelCatalogFindModel,
|
|
81
|
+
WinMLModelCatalogFindModelAsync,
|
|
82
|
+
WinMLModelCatalogFindModelGetResult,
|
|
83
|
+
WinMLModelCatalogGetAvailableModel,
|
|
84
|
+
WinMLModelCatalogGetAvailableModels,
|
|
85
|
+
WinMLModelCatalogRelease,
|
|
86
|
+
WinMLModelCatalogSetExecutionProviders,
|
|
87
|
+
WinMLModelCatalogSourceCreateFromUri,
|
|
88
|
+
WinMLModelCatalogSourceCreateFromUriAsync,
|
|
89
|
+
WinMLModelCatalogSourceCreateFromUriWithHeaders,
|
|
90
|
+
WinMLModelCatalogSourceCreateFromUriWithHeadersAsync,
|
|
91
|
+
WinMLModelCatalogSourceGetId,
|
|
92
|
+
WinMLModelCatalogSourceGetIdSize,
|
|
93
|
+
WinMLModelCatalogSourceGetResult,
|
|
94
|
+
WinMLModelCatalogSourceGetUri,
|
|
95
|
+
WinMLModelCatalogSourceGetUriSize,
|
|
96
|
+
WinMLModelCatalogSourceRelease,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
__all__ = [
|
|
100
|
+
"EpReadyState",
|
|
101
|
+
"EpCertification",
|
|
102
|
+
"CatalogModelInstanceStatus",
|
|
103
|
+
"CatalogModelStatus",
|
|
104
|
+
"ExecutionProvider",
|
|
105
|
+
"EpCatalog",
|
|
106
|
+
"AsyncOperation",
|
|
107
|
+
"ModelCatalogSource",
|
|
108
|
+
"ModelCatalog",
|
|
109
|
+
"CatalogModelInfo",
|
|
110
|
+
"CatalogModelInstance",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# ---------------------------------------------------------------------------
|
|
115
|
+
# Helpers
|
|
116
|
+
# ---------------------------------------------------------------------------
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _get_ep_string(handle, get_size_fn, get_fn) -> str:
|
|
120
|
+
"""Read a variable-length string property from an EP handle."""
|
|
121
|
+
size = ctypes.c_size_t()
|
|
122
|
+
get_size_fn(handle, ctypes.byref(size))
|
|
123
|
+
if size.value == 0:
|
|
124
|
+
return ""
|
|
125
|
+
buf = ctypes.create_string_buffer(size.value)
|
|
126
|
+
used = ctypes.c_size_t()
|
|
127
|
+
get_fn(handle, size.value, buf, ctypes.byref(used))
|
|
128
|
+
return buf.value.decode("utf-8")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _enum_strings(handle, enum_fn) -> list[str]:
|
|
132
|
+
"""Collect strings from a WinMLStringEnumCallback-based enumeration."""
|
|
133
|
+
results: list[str] = []
|
|
134
|
+
|
|
135
|
+
@StringEnumCallback
|
|
136
|
+
def _callback(value, context):
|
|
137
|
+
try:
|
|
138
|
+
results.append(value.decode("utf-8"))
|
|
139
|
+
except Exception:
|
|
140
|
+
return False
|
|
141
|
+
return True
|
|
142
|
+
|
|
143
|
+
enum_fn(handle, _callback, None)
|
|
144
|
+
return results
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _make_header_arrays(headers: dict[str, str]):
|
|
148
|
+
"""Convert a dict of headers to ctypes arrays for C API calls."""
|
|
149
|
+
keys = list(headers.keys())
|
|
150
|
+
values = list(headers.values())
|
|
151
|
+
count = len(keys)
|
|
152
|
+
keys_arr = (ctypes.c_char_p * count)(*(k.encode("utf-8") for k in keys))
|
|
153
|
+
values_arr = (ctypes.c_char_p * count)(*(v.encode("utf-8") for v in values))
|
|
154
|
+
return count, keys_arr, values_arr
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# ---------------------------------------------------------------------------
|
|
158
|
+
# ExecutionProvider
|
|
159
|
+
# ---------------------------------------------------------------------------
|
|
160
|
+
|
|
161
|
+
class ExecutionProvider:
|
|
162
|
+
"""Handle to a discovered Windows ML execution provider.
|
|
163
|
+
|
|
164
|
+
Instances are obtained from :meth:`EpCatalog.find_provider`.
|
|
165
|
+
The handle is owned by the catalog and must not outlive it.
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
def __init__(self, handle) -> None:
|
|
169
|
+
self._handle = handle
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def name(self) -> str:
|
|
173
|
+
return _get_ep_string(self._handle, WinMLEpGetNameSize, WinMLEpGetName)
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def version(self) -> str:
|
|
177
|
+
return _get_ep_string(self._handle, WinMLEpGetVersionSize, WinMLEpGetVersion)
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def package_family_name(self) -> str:
|
|
181
|
+
return _get_ep_string(
|
|
182
|
+
self._handle, WinMLEpGetPackageFamilyNameSize, WinMLEpGetPackageFamilyName
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def library_path(self) -> str:
|
|
187
|
+
return _get_ep_string(
|
|
188
|
+
self._handle, WinMLEpGetLibraryPathSize, WinMLEpGetLibraryPath
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def package_root_path(self) -> str:
|
|
193
|
+
return _get_ep_string(
|
|
194
|
+
self._handle, WinMLEpGetPackageRootPathSize, WinMLEpGetPackageRootPath
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def ready_state(self) -> EpReadyState:
|
|
199
|
+
state = ctypes.c_int()
|
|
200
|
+
WinMLEpGetReadyState(self._handle, ctypes.byref(state))
|
|
201
|
+
return EpReadyState(state.value)
|
|
202
|
+
|
|
203
|
+
@property
|
|
204
|
+
def certification(self) -> EpCertification:
|
|
205
|
+
cert = ctypes.c_int()
|
|
206
|
+
WinMLEpGetCertification(self._handle, ctypes.byref(cert))
|
|
207
|
+
return EpCertification(cert.value)
|
|
208
|
+
|
|
209
|
+
def ensure_ready(self) -> None:
|
|
210
|
+
"""Block until the execution provider is ready.
|
|
211
|
+
|
|
212
|
+
Raises :class:`OSError` on failure.
|
|
213
|
+
"""
|
|
214
|
+
WinMLEpEnsureReady(self._handle)
|
|
215
|
+
|
|
216
|
+
def ensure_ready_async(
|
|
217
|
+
self,
|
|
218
|
+
on_complete: Optional[Callable[[], None]] = None,
|
|
219
|
+
on_progress: Optional[Callable[[float], None]] = None,
|
|
220
|
+
) -> "AsyncOperation":
|
|
221
|
+
"""Start an asynchronous readiness check.
|
|
222
|
+
|
|
223
|
+
Returns an :class:`AsyncOperation` that can be used to poll, wait,
|
|
224
|
+
or cancel the operation.
|
|
225
|
+
"""
|
|
226
|
+
return AsyncOperation(
|
|
227
|
+
WinMLEpEnsureReadyAsync, self._handle,
|
|
228
|
+
on_complete=on_complete, on_progress=on_progress,
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
def __repr__(self) -> str:
|
|
232
|
+
return f"ExecutionProvider(name={self.name!r})"
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
# ---------------------------------------------------------------------------
|
|
236
|
+
# AsyncOperation
|
|
237
|
+
# ---------------------------------------------------------------------------
|
|
238
|
+
|
|
239
|
+
# Prevent GC of in-flight async operations. The completion callback removes
|
|
240
|
+
# the entry once the native operation finishes.
|
|
241
|
+
_live_operations: set["AsyncOperation"] = set()
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
class AsyncOperation:
|
|
245
|
+
"""Wraps a ``WinMLAsyncBlock`` for asynchronous operations."""
|
|
246
|
+
|
|
247
|
+
def __init__(
|
|
248
|
+
self,
|
|
249
|
+
start_fn,
|
|
250
|
+
*args,
|
|
251
|
+
result_fn: Optional[Callable] = None,
|
|
252
|
+
on_complete: Optional[Callable[[], None]] = None,
|
|
253
|
+
on_progress: Optional[Callable[[float], None]] = None,
|
|
254
|
+
) -> None:
|
|
255
|
+
"""Create and start an async operation.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
start_fn: Native function that initiates the async work. It must
|
|
259
|
+
accept ``(*args, async_block)`` - i.e. the caller-supplied
|
|
260
|
+
positional arguments followed by a pointer to a
|
|
261
|
+
``WinMLAsyncBlock`` as the **last** parameter.
|
|
262
|
+
*args: Positional arguments forwarded to *start_fn* before the
|
|
263
|
+
async block.
|
|
264
|
+
result_fn: Optional callable to extract a result from the
|
|
265
|
+
completed async block. If provided, :meth:`get_result`
|
|
266
|
+
becomes available.
|
|
267
|
+
on_complete: Optional callback invoked when the operation finishes.
|
|
268
|
+
on_progress: Optional callback invoked with progress (0.0-1.0).
|
|
269
|
+
"""
|
|
270
|
+
self._closed = False
|
|
271
|
+
self._result_fn = result_fn
|
|
272
|
+
|
|
273
|
+
# Track live operations so the GC cannot destroy an AsyncOperation
|
|
274
|
+
# (and its native AsyncBlock) while the native thread is still running.
|
|
275
|
+
_live_operations.add(self)
|
|
276
|
+
|
|
277
|
+
# Build native callbacks. Must be stored as instance attributes to
|
|
278
|
+
# prevent garbage collection while the async operation is in flight.
|
|
279
|
+
# Exceptions in user callbacks are caught to avoid propagating Python
|
|
280
|
+
# exceptions through native call frames (undefined behavior).
|
|
281
|
+
if on_complete is not None:
|
|
282
|
+
_user_complete = on_complete
|
|
283
|
+
|
|
284
|
+
@AsyncCompletionCallback
|
|
285
|
+
def _on_complete(async_ptr):
|
|
286
|
+
try:
|
|
287
|
+
_user_complete()
|
|
288
|
+
except Exception:
|
|
289
|
+
pass
|
|
290
|
+
finally:
|
|
291
|
+
_live_operations.discard(self)
|
|
292
|
+
|
|
293
|
+
self._completion_cb = _on_complete
|
|
294
|
+
else:
|
|
295
|
+
@AsyncCompletionCallback
|
|
296
|
+
def _on_complete_default(async_ptr):
|
|
297
|
+
_live_operations.discard(self)
|
|
298
|
+
|
|
299
|
+
self._completion_cb = _on_complete_default
|
|
300
|
+
|
|
301
|
+
if on_progress is not None:
|
|
302
|
+
_user_progress = on_progress
|
|
303
|
+
|
|
304
|
+
@AsyncProgressCallback
|
|
305
|
+
def _on_progress(async_ptr, value):
|
|
306
|
+
try:
|
|
307
|
+
_user_progress(value)
|
|
308
|
+
except Exception:
|
|
309
|
+
pass
|
|
310
|
+
|
|
311
|
+
self._progress_cb = _on_progress
|
|
312
|
+
else:
|
|
313
|
+
self._progress_cb = AsyncProgressCallback()
|
|
314
|
+
|
|
315
|
+
self._block = AsyncBlock()
|
|
316
|
+
self._block.context = None
|
|
317
|
+
self._block.callback = self._completion_cb
|
|
318
|
+
self._block.progress = self._progress_cb
|
|
319
|
+
|
|
320
|
+
try:
|
|
321
|
+
start_fn(*args, ctypes.byref(self._block))
|
|
322
|
+
except BaseException:
|
|
323
|
+
_live_operations.discard(self)
|
|
324
|
+
raise
|
|
325
|
+
|
|
326
|
+
def get_status(self, wait: bool = False) -> None:
|
|
327
|
+
"""Poll or wait for the async operation status.
|
|
328
|
+
|
|
329
|
+
Raises :class:`OSError` if the operation failed.
|
|
330
|
+
"""
|
|
331
|
+
WinMLAsyncGetStatus(ctypes.byref(self._block), wait)
|
|
332
|
+
|
|
333
|
+
def wait(self) -> None:
|
|
334
|
+
"""Block until the async operation completes.
|
|
335
|
+
|
|
336
|
+
Raises :class:`OSError` if the operation failed.
|
|
337
|
+
"""
|
|
338
|
+
self.get_status(wait=True)
|
|
339
|
+
|
|
340
|
+
def cancel(self) -> None:
|
|
341
|
+
"""Request cancellation of the async operation."""
|
|
342
|
+
WinMLAsyncCancel(ctypes.byref(self._block))
|
|
343
|
+
|
|
344
|
+
def get_result(self):
|
|
345
|
+
"""Extract the result after the async operation has completed.
|
|
346
|
+
|
|
347
|
+
Only available for operations started with a *result_fn*.
|
|
348
|
+
|
|
349
|
+
Raises:
|
|
350
|
+
RuntimeError: If no result function was provided.
|
|
351
|
+
"""
|
|
352
|
+
if self._result_fn is None:
|
|
353
|
+
raise RuntimeError("This operation does not produce a result")
|
|
354
|
+
return self._result_fn(ctypes.byref(self._block))
|
|
355
|
+
|
|
356
|
+
def close(self) -> None:
|
|
357
|
+
"""Release async resources.
|
|
358
|
+
|
|
359
|
+
Waits for the operation to complete before releasing the async block
|
|
360
|
+
to avoid destroying it while the native thread is still running.
|
|
361
|
+
"""
|
|
362
|
+
if not self._closed:
|
|
363
|
+
# Wait for the native operation to finish before freeing the block.
|
|
364
|
+
try:
|
|
365
|
+
WinMLAsyncGetStatus(ctypes.byref(self._block), True)
|
|
366
|
+
except OSError:
|
|
367
|
+
pass
|
|
368
|
+
WinMLAsyncClose(ctypes.byref(self._block))
|
|
369
|
+
self._closed = True
|
|
370
|
+
_live_operations.discard(self)
|
|
371
|
+
|
|
372
|
+
def __enter__(self) -> "AsyncOperation":
|
|
373
|
+
return self
|
|
374
|
+
|
|
375
|
+
def __exit__(self, *args) -> None:
|
|
376
|
+
self.close()
|
|
377
|
+
|
|
378
|
+
def __del__(self) -> None:
|
|
379
|
+
self.close()
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
# ---------------------------------------------------------------------------
|
|
383
|
+
# EpCatalog
|
|
384
|
+
# ---------------------------------------------------------------------------
|
|
385
|
+
|
|
386
|
+
class EpCatalog:
|
|
387
|
+
"""Windows ML Execution Provider Catalog.
|
|
388
|
+
|
|
389
|
+
Use as a context manager::
|
|
390
|
+
|
|
391
|
+
with EpCatalog() as catalog:
|
|
392
|
+
for ep in catalog.find_all_providers():
|
|
393
|
+
print(ep.name, ep.ready_state)
|
|
394
|
+
"""
|
|
395
|
+
|
|
396
|
+
def __init__(self) -> None:
|
|
397
|
+
handle = EpCatalogHandle()
|
|
398
|
+
WinMLEpCatalogCreate(ctypes.byref(handle))
|
|
399
|
+
self._handle = handle
|
|
400
|
+
|
|
401
|
+
def find_all_providers(self) -> list[ExecutionProvider]:
|
|
402
|
+
"""Discover all registered execution providers.
|
|
403
|
+
|
|
404
|
+
Returns a list of :class:`ExecutionProvider` handles.
|
|
405
|
+
|
|
406
|
+
Raises:
|
|
407
|
+
RuntimeError: If the catalog has been closed.
|
|
408
|
+
"""
|
|
409
|
+
if not self._handle:
|
|
410
|
+
raise RuntimeError("EpCatalog has been closed")
|
|
411
|
+
providers: list[ExecutionProvider] = []
|
|
412
|
+
|
|
413
|
+
@EpEnumCallback
|
|
414
|
+
def _callback(ep, info_ptr, context):
|
|
415
|
+
try:
|
|
416
|
+
providers.append(ExecutionProvider(ep))
|
|
417
|
+
except Exception:
|
|
418
|
+
return False
|
|
419
|
+
return True
|
|
420
|
+
|
|
421
|
+
WinMLEpCatalogEnumProviders(self._handle, _callback, None)
|
|
422
|
+
|
|
423
|
+
return providers
|
|
424
|
+
|
|
425
|
+
def close(self) -> None:
|
|
426
|
+
"""Release the catalog and all associated EP handles."""
|
|
427
|
+
if self._handle:
|
|
428
|
+
WinMLEpCatalogRelease(self._handle)
|
|
429
|
+
self._handle = None
|
|
430
|
+
|
|
431
|
+
def __enter__(self) -> "EpCatalog":
|
|
432
|
+
return self
|
|
433
|
+
|
|
434
|
+
def __exit__(self, *args) -> None:
|
|
435
|
+
self.close()
|
|
436
|
+
|
|
437
|
+
def __del__(self) -> None:
|
|
438
|
+
try:
|
|
439
|
+
self.close()
|
|
440
|
+
except Exception:
|
|
441
|
+
pass
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
# ---------------------------------------------------------------------------
|
|
445
|
+
# ModelCatalogSource
|
|
446
|
+
# ---------------------------------------------------------------------------
|
|
447
|
+
|
|
448
|
+
class ModelCatalogSource:
|
|
449
|
+
"""Represents a model catalog source endpoint.
|
|
450
|
+
|
|
451
|
+
Create from a URI::
|
|
452
|
+
|
|
453
|
+
source = ModelCatalogSource.create_from_uri("https://example.com/catalog")
|
|
454
|
+
|
|
455
|
+
Or with custom headers::
|
|
456
|
+
|
|
457
|
+
source = ModelCatalogSource.create_from_uri_with_headers(
|
|
458
|
+
"https://example.com/catalog",
|
|
459
|
+
{"Authorization": "Bearer token"},
|
|
460
|
+
)
|
|
461
|
+
"""
|
|
462
|
+
|
|
463
|
+
def __init__(self, handle) -> None:
|
|
464
|
+
self._handle = handle
|
|
465
|
+
|
|
466
|
+
@staticmethod
|
|
467
|
+
def create_from_uri(uri: str) -> "ModelCatalogSource":
|
|
468
|
+
"""Create a catalog source from a URI (blocking)."""
|
|
469
|
+
handle = ModelCatalogSourceHandle()
|
|
470
|
+
WinMLModelCatalogSourceCreateFromUri(
|
|
471
|
+
uri.encode("utf-8"), ctypes.byref(handle)
|
|
472
|
+
)
|
|
473
|
+
return ModelCatalogSource(handle)
|
|
474
|
+
|
|
475
|
+
@staticmethod
|
|
476
|
+
def create_from_uri_async(
|
|
477
|
+
uri: str,
|
|
478
|
+
on_complete: Optional[Callable[[], None]] = None,
|
|
479
|
+
on_progress: Optional[Callable[[float], None]] = None,
|
|
480
|
+
) -> "AsyncOperation":
|
|
481
|
+
"""Create a catalog source from a URI (async).
|
|
482
|
+
|
|
483
|
+
Call :meth:`AsyncOperation.get_result` after completion to obtain
|
|
484
|
+
the :class:`ModelCatalogSource`.
|
|
485
|
+
"""
|
|
486
|
+
def _extract(block_ptr):
|
|
487
|
+
handle = ModelCatalogSourceHandle()
|
|
488
|
+
WinMLModelCatalogSourceGetResult(block_ptr, ctypes.byref(handle))
|
|
489
|
+
return ModelCatalogSource(handle)
|
|
490
|
+
|
|
491
|
+
return AsyncOperation(
|
|
492
|
+
WinMLModelCatalogSourceCreateFromUriAsync,
|
|
493
|
+
uri.encode("utf-8"),
|
|
494
|
+
result_fn=_extract,
|
|
495
|
+
on_complete=on_complete,
|
|
496
|
+
on_progress=on_progress,
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
@staticmethod
|
|
500
|
+
def create_from_uri_with_headers(
|
|
501
|
+
uri: str, headers: dict[str, str],
|
|
502
|
+
) -> "ModelCatalogSource":
|
|
503
|
+
"""Create a catalog source from a URI with custom HTTP headers (blocking)."""
|
|
504
|
+
count, keys_arr, values_arr = _make_header_arrays(headers)
|
|
505
|
+
handle = ModelCatalogSourceHandle()
|
|
506
|
+
WinMLModelCatalogSourceCreateFromUriWithHeaders(
|
|
507
|
+
uri.encode("utf-8"), count, keys_arr, values_arr, ctypes.byref(handle)
|
|
508
|
+
)
|
|
509
|
+
return ModelCatalogSource(handle)
|
|
510
|
+
|
|
511
|
+
@staticmethod
|
|
512
|
+
def create_from_uri_with_headers_async(
|
|
513
|
+
uri: str,
|
|
514
|
+
headers: dict[str, str],
|
|
515
|
+
on_complete: Optional[Callable[[], None]] = None,
|
|
516
|
+
on_progress: Optional[Callable[[float], None]] = None,
|
|
517
|
+
) -> "AsyncOperation":
|
|
518
|
+
"""Create a catalog source from a URI with custom HTTP headers (async).
|
|
519
|
+
|
|
520
|
+
Call :meth:`AsyncOperation.get_result` after completion to obtain
|
|
521
|
+
the :class:`ModelCatalogSource`.
|
|
522
|
+
"""
|
|
523
|
+
count, keys_arr, values_arr = _make_header_arrays(headers)
|
|
524
|
+
|
|
525
|
+
def _extract(block_ptr):
|
|
526
|
+
handle = ModelCatalogSourceHandle()
|
|
527
|
+
WinMLModelCatalogSourceGetResult(block_ptr, ctypes.byref(handle))
|
|
528
|
+
return ModelCatalogSource(handle)
|
|
529
|
+
|
|
530
|
+
return AsyncOperation(
|
|
531
|
+
WinMLModelCatalogSourceCreateFromUriWithHeadersAsync,
|
|
532
|
+
uri.encode("utf-8"), count, keys_arr, values_arr,
|
|
533
|
+
result_fn=_extract,
|
|
534
|
+
on_complete=on_complete,
|
|
535
|
+
on_progress=on_progress,
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
@property
|
|
539
|
+
def id(self) -> str:
|
|
540
|
+
return _get_ep_string(
|
|
541
|
+
self._handle, WinMLModelCatalogSourceGetIdSize, WinMLModelCatalogSourceGetId
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
@property
|
|
545
|
+
def uri(self) -> str:
|
|
546
|
+
return _get_ep_string(
|
|
547
|
+
self._handle, WinMLModelCatalogSourceGetUriSize, WinMLModelCatalogSourceGetUri
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
def close(self) -> None:
|
|
551
|
+
"""Release the catalog source handle."""
|
|
552
|
+
if self._handle:
|
|
553
|
+
WinMLModelCatalogSourceRelease(self._handle)
|
|
554
|
+
self._handle = None
|
|
555
|
+
|
|
556
|
+
def __enter__(self) -> "ModelCatalogSource":
|
|
557
|
+
return self
|
|
558
|
+
|
|
559
|
+
def __exit__(self, *args) -> None:
|
|
560
|
+
self.close()
|
|
561
|
+
|
|
562
|
+
def __del__(self) -> None:
|
|
563
|
+
try:
|
|
564
|
+
self.close()
|
|
565
|
+
except Exception:
|
|
566
|
+
pass
|
|
567
|
+
|
|
568
|
+
def __repr__(self) -> str:
|
|
569
|
+
return f"ModelCatalogSource(id={self.id!r})"
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
# ---------------------------------------------------------------------------
|
|
573
|
+
# ModelCatalog
|
|
574
|
+
# ---------------------------------------------------------------------------
|
|
575
|
+
|
|
576
|
+
class ModelCatalog:
|
|
577
|
+
"""Windows ML Model Catalog.
|
|
578
|
+
|
|
579
|
+
Use as a context manager::
|
|
580
|
+
|
|
581
|
+
with ModelCatalogSource.create_from_uri(uri) as source:
|
|
582
|
+
with ModelCatalog([source]) as catalog:
|
|
583
|
+
for model in catalog.find_all_models():
|
|
584
|
+
print(model.name)
|
|
585
|
+
"""
|
|
586
|
+
|
|
587
|
+
def __init__(self, sources: list[ModelCatalogSource]) -> None:
|
|
588
|
+
count = len(sources)
|
|
589
|
+
arr = (ModelCatalogSourceHandle * count)(
|
|
590
|
+
*(s._handle for s in sources)
|
|
591
|
+
)
|
|
592
|
+
handle = ModelCatalogHandle()
|
|
593
|
+
WinMLModelCatalogCreate(count, arr, ctypes.byref(handle))
|
|
594
|
+
self._handle = handle
|
|
595
|
+
|
|
596
|
+
@property
|
|
597
|
+
def execution_providers(self) -> list[str]:
|
|
598
|
+
"""List the execution providers configured on this catalog."""
|
|
599
|
+
if not self._handle:
|
|
600
|
+
raise RuntimeError("ModelCatalog has been closed")
|
|
601
|
+
return _enum_strings(self._handle, WinMLModelCatalogEnumExecutionProviders)
|
|
602
|
+
|
|
603
|
+
def set_execution_providers(self, providers: list[str]) -> None:
|
|
604
|
+
"""Set the execution providers to use for model queries."""
|
|
605
|
+
if not self._handle:
|
|
606
|
+
raise RuntimeError("ModelCatalog has been closed")
|
|
607
|
+
count = len(providers)
|
|
608
|
+
arr = (ctypes.c_char_p * count)(*(p.encode("utf-8") for p in providers))
|
|
609
|
+
WinMLModelCatalogSetExecutionProviders(self._handle, count, arr)
|
|
610
|
+
|
|
611
|
+
def get_available_model(self, id_or_name: str) -> "CatalogModelInfo":
|
|
612
|
+
"""Look up a single available model by ID or name."""
|
|
613
|
+
if not self._handle:
|
|
614
|
+
raise RuntimeError("ModelCatalog has been closed")
|
|
615
|
+
handle = CatalogModelInfoHandle()
|
|
616
|
+
WinMLModelCatalogGetAvailableModel(
|
|
617
|
+
self._handle, id_or_name.encode("utf-8"), ctypes.byref(handle)
|
|
618
|
+
)
|
|
619
|
+
return CatalogModelInfo(handle)
|
|
620
|
+
|
|
621
|
+
def get_available_models(self) -> list["CatalogModelInfo"]:
|
|
622
|
+
"""Enumerate all available models."""
|
|
623
|
+
if not self._handle:
|
|
624
|
+
raise RuntimeError("ModelCatalog has been closed")
|
|
625
|
+
models: list[CatalogModelInfo] = []
|
|
626
|
+
|
|
627
|
+
@CatalogModelInfoEnumCallback
|
|
628
|
+
def _callback(model_info, context):
|
|
629
|
+
try:
|
|
630
|
+
models.append(CatalogModelInfo(model_info))
|
|
631
|
+
except Exception:
|
|
632
|
+
return False
|
|
633
|
+
return True
|
|
634
|
+
|
|
635
|
+
WinMLModelCatalogGetAvailableModels(self._handle, _callback, None)
|
|
636
|
+
return models
|
|
637
|
+
|
|
638
|
+
def find_model(self, id_or_name: str) -> "CatalogModelInfo":
|
|
639
|
+
"""Find a model by ID or name (blocking)."""
|
|
640
|
+
if not self._handle:
|
|
641
|
+
raise RuntimeError("ModelCatalog has been closed")
|
|
642
|
+
handle = CatalogModelInfoHandle()
|
|
643
|
+
WinMLModelCatalogFindModel(
|
|
644
|
+
self._handle, id_or_name.encode("utf-8"), ctypes.byref(handle)
|
|
645
|
+
)
|
|
646
|
+
return CatalogModelInfo(handle)
|
|
647
|
+
|
|
648
|
+
def find_model_async(
|
|
649
|
+
self,
|
|
650
|
+
id_or_name: str,
|
|
651
|
+
on_complete: Optional[Callable[[], None]] = None,
|
|
652
|
+
on_progress: Optional[Callable[[float], None]] = None,
|
|
653
|
+
) -> "AsyncOperation":
|
|
654
|
+
"""Find a model by ID or name (async).
|
|
655
|
+
|
|
656
|
+
Call :meth:`AsyncOperation.get_result` after completion to obtain
|
|
657
|
+
the :class:`CatalogModelInfo`.
|
|
658
|
+
"""
|
|
659
|
+
if not self._handle:
|
|
660
|
+
raise RuntimeError("ModelCatalog has been closed")
|
|
661
|
+
|
|
662
|
+
def _extract(block_ptr):
|
|
663
|
+
handle = CatalogModelInfoHandle()
|
|
664
|
+
WinMLModelCatalogFindModelGetResult(block_ptr, ctypes.byref(handle))
|
|
665
|
+
return CatalogModelInfo(handle)
|
|
666
|
+
|
|
667
|
+
return AsyncOperation(
|
|
668
|
+
WinMLModelCatalogFindModelAsync,
|
|
669
|
+
self._handle, id_or_name.encode("utf-8"),
|
|
670
|
+
result_fn=_extract,
|
|
671
|
+
on_complete=on_complete,
|
|
672
|
+
on_progress=on_progress,
|
|
673
|
+
)
|
|
674
|
+
|
|
675
|
+
def find_all_models(self) -> list["CatalogModelInfo"]:
|
|
676
|
+
"""Find all models (blocking)."""
|
|
677
|
+
if not self._handle:
|
|
678
|
+
raise RuntimeError("ModelCatalog has been closed")
|
|
679
|
+
models: list[CatalogModelInfo] = []
|
|
680
|
+
|
|
681
|
+
@CatalogModelInfoEnumCallback
|
|
682
|
+
def _callback(model_info, context):
|
|
683
|
+
try:
|
|
684
|
+
models.append(CatalogModelInfo(model_info))
|
|
685
|
+
except Exception:
|
|
686
|
+
return False
|
|
687
|
+
return True
|
|
688
|
+
|
|
689
|
+
WinMLModelCatalogFindAllModels(self._handle, _callback, None)
|
|
690
|
+
return models
|
|
691
|
+
|
|
692
|
+
def find_all_models_async(
|
|
693
|
+
self,
|
|
694
|
+
on_complete: Optional[Callable[[], None]] = None,
|
|
695
|
+
on_progress: Optional[Callable[[float], None]] = None,
|
|
696
|
+
) -> "AsyncOperation":
|
|
697
|
+
"""Find all models (async).
|
|
698
|
+
|
|
699
|
+
Call :meth:`AsyncOperation.get_result` after completion to obtain
|
|
700
|
+
a list of :class:`CatalogModelInfo`.
|
|
701
|
+
"""
|
|
702
|
+
if not self._handle:
|
|
703
|
+
raise RuntimeError("ModelCatalog has been closed")
|
|
704
|
+
|
|
705
|
+
def _extract(block_ptr):
|
|
706
|
+
models: list[CatalogModelInfo] = []
|
|
707
|
+
|
|
708
|
+
@CatalogModelInfoEnumCallback
|
|
709
|
+
def _callback(model_info, context):
|
|
710
|
+
try:
|
|
711
|
+
models.append(CatalogModelInfo(model_info))
|
|
712
|
+
except Exception:
|
|
713
|
+
return False
|
|
714
|
+
return True
|
|
715
|
+
|
|
716
|
+
WinMLModelCatalogFindAllModelsGetResult(block_ptr, _callback, None)
|
|
717
|
+
return models
|
|
718
|
+
|
|
719
|
+
return AsyncOperation(
|
|
720
|
+
WinMLModelCatalogFindAllModelsAsync,
|
|
721
|
+
self._handle,
|
|
722
|
+
result_fn=_extract,
|
|
723
|
+
on_complete=on_complete,
|
|
724
|
+
on_progress=on_progress,
|
|
725
|
+
)
|
|
726
|
+
|
|
727
|
+
def close(self) -> None:
|
|
728
|
+
"""Release the model catalog."""
|
|
729
|
+
if self._handle:
|
|
730
|
+
WinMLModelCatalogRelease(self._handle)
|
|
731
|
+
self._handle = None
|
|
732
|
+
|
|
733
|
+
def __enter__(self) -> "ModelCatalog":
|
|
734
|
+
return self
|
|
735
|
+
|
|
736
|
+
def __exit__(self, *args) -> None:
|
|
737
|
+
self.close()
|
|
738
|
+
|
|
739
|
+
def __del__(self) -> None:
|
|
740
|
+
try:
|
|
741
|
+
self.close()
|
|
742
|
+
except Exception:
|
|
743
|
+
pass
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
# ---------------------------------------------------------------------------
|
|
747
|
+
# CatalogModelInfo
|
|
748
|
+
# ---------------------------------------------------------------------------
|
|
749
|
+
|
|
750
|
+
class CatalogModelInfo:
|
|
751
|
+
"""Metadata about a model in the catalog.
|
|
752
|
+
|
|
753
|
+
Obtained from :meth:`ModelCatalog.find_model` or enumeration methods.
|
|
754
|
+
"""
|
|
755
|
+
|
|
756
|
+
def __init__(self, handle) -> None:
|
|
757
|
+
self._handle = handle
|
|
758
|
+
|
|
759
|
+
@property
|
|
760
|
+
def id(self) -> str:
|
|
761
|
+
return _get_ep_string(
|
|
762
|
+
self._handle, WinMLCatalogModelInfoGetIdSize, WinMLCatalogModelInfoGetId
|
|
763
|
+
)
|
|
764
|
+
|
|
765
|
+
@property
|
|
766
|
+
def name(self) -> str:
|
|
767
|
+
return _get_ep_string(
|
|
768
|
+
self._handle, WinMLCatalogModelInfoGetNameSize, WinMLCatalogModelInfoGetName
|
|
769
|
+
)
|
|
770
|
+
|
|
771
|
+
@property
|
|
772
|
+
def publisher(self) -> str:
|
|
773
|
+
return _get_ep_string(
|
|
774
|
+
self._handle,
|
|
775
|
+
WinMLCatalogModelInfoGetPublisherSize,
|
|
776
|
+
WinMLCatalogModelInfoGetPublisher,
|
|
777
|
+
)
|
|
778
|
+
|
|
779
|
+
@property
|
|
780
|
+
def source_id(self) -> str:
|
|
781
|
+
return _get_ep_string(
|
|
782
|
+
self._handle,
|
|
783
|
+
WinMLCatalogModelInfoGetSourceIdSize,
|
|
784
|
+
WinMLCatalogModelInfoGetSourceId,
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
@property
|
|
788
|
+
def version(self) -> str:
|
|
789
|
+
return _get_ep_string(
|
|
790
|
+
self._handle,
|
|
791
|
+
WinMLCatalogModelInfoGetVersionSize,
|
|
792
|
+
WinMLCatalogModelInfoGetVersion,
|
|
793
|
+
)
|
|
794
|
+
|
|
795
|
+
@property
|
|
796
|
+
def license(self) -> str:
|
|
797
|
+
return _get_ep_string(
|
|
798
|
+
self._handle,
|
|
799
|
+
WinMLCatalogModelInfoGetLicenseSize,
|
|
800
|
+
WinMLCatalogModelInfoGetLicense,
|
|
801
|
+
)
|
|
802
|
+
|
|
803
|
+
@property
|
|
804
|
+
def license_uri(self) -> str:
|
|
805
|
+
return _get_ep_string(
|
|
806
|
+
self._handle,
|
|
807
|
+
WinMLCatalogModelInfoGetLicenseUriSize,
|
|
808
|
+
WinMLCatalogModelInfoGetLicenseUri,
|
|
809
|
+
)
|
|
810
|
+
|
|
811
|
+
@property
|
|
812
|
+
def license_text(self) -> str:
|
|
813
|
+
return _get_ep_string(
|
|
814
|
+
self._handle,
|
|
815
|
+
WinMLCatalogModelInfoGetLicenseTextSize,
|
|
816
|
+
WinMLCatalogModelInfoGetLicenseText,
|
|
817
|
+
)
|
|
818
|
+
|
|
819
|
+
@property
|
|
820
|
+
def uri(self) -> str:
|
|
821
|
+
return _get_ep_string(
|
|
822
|
+
self._handle, WinMLCatalogModelInfoGetUriSize, WinMLCatalogModelInfoGetUri
|
|
823
|
+
)
|
|
824
|
+
|
|
825
|
+
@property
|
|
826
|
+
def model_size_in_bytes(self) -> int:
|
|
827
|
+
size = ctypes.c_uint64()
|
|
828
|
+
WinMLCatalogModelInfoGetModelSizeInBytes(self._handle, ctypes.byref(size))
|
|
829
|
+
return size.value
|
|
830
|
+
|
|
831
|
+
@property
|
|
832
|
+
def execution_providers(self) -> list[str]:
|
|
833
|
+
return _enum_strings(
|
|
834
|
+
self._handle, WinMLCatalogModelInfoEnumExecutionProviders
|
|
835
|
+
)
|
|
836
|
+
|
|
837
|
+
@property
|
|
838
|
+
def status(self) -> CatalogModelStatus:
|
|
839
|
+
val = ctypes.c_int()
|
|
840
|
+
WinMLCatalogModelInfoGetStatus(self._handle, ctypes.byref(val))
|
|
841
|
+
return CatalogModelStatus(val.value)
|
|
842
|
+
|
|
843
|
+
def get_instance_async(
|
|
844
|
+
self,
|
|
845
|
+
on_complete: Optional[Callable[[], None]] = None,
|
|
846
|
+
on_progress: Optional[Callable[[float], None]] = None,
|
|
847
|
+
) -> "AsyncOperation":
|
|
848
|
+
"""Download or prepare a model instance (async).
|
|
849
|
+
|
|
850
|
+
Call :meth:`AsyncOperation.get_result` after completion to obtain
|
|
851
|
+
the :class:`CatalogModelInstance`.
|
|
852
|
+
"""
|
|
853
|
+
def _extract(block_ptr):
|
|
854
|
+
result = CatalogModelInstanceResult()
|
|
855
|
+
WinMLCatalogModelInfoGetInstanceResult(block_ptr, ctypes.byref(result))
|
|
856
|
+
if result.extendedError < 0:
|
|
857
|
+
raise OSError(
|
|
858
|
+
f"GetInstance failed: 0x{result.extendedError & 0xFFFFFFFF:08X}"
|
|
859
|
+
)
|
|
860
|
+
return CatalogModelInstance(result.instance)
|
|
861
|
+
|
|
862
|
+
return AsyncOperation(
|
|
863
|
+
WinMLCatalogModelInfoGetInstanceAsync,
|
|
864
|
+
self._handle,
|
|
865
|
+
result_fn=_extract,
|
|
866
|
+
on_complete=on_complete,
|
|
867
|
+
on_progress=on_progress,
|
|
868
|
+
)
|
|
869
|
+
|
|
870
|
+
def get_instance_with_headers_async(
|
|
871
|
+
self,
|
|
872
|
+
headers: dict[str, str],
|
|
873
|
+
on_complete: Optional[Callable[[], None]] = None,
|
|
874
|
+
on_progress: Optional[Callable[[float], None]] = None,
|
|
875
|
+
) -> "AsyncOperation":
|
|
876
|
+
"""Download or prepare a model instance with custom HTTP headers (async).
|
|
877
|
+
|
|
878
|
+
Call :meth:`AsyncOperation.get_result` after completion to obtain
|
|
879
|
+
the :class:`CatalogModelInstance`.
|
|
880
|
+
"""
|
|
881
|
+
count, keys_arr, values_arr = _make_header_arrays(headers)
|
|
882
|
+
|
|
883
|
+
def _extract(block_ptr):
|
|
884
|
+
result = CatalogModelInstanceResult()
|
|
885
|
+
WinMLCatalogModelInfoGetInstanceResult(block_ptr, ctypes.byref(result))
|
|
886
|
+
if result.extendedError < 0:
|
|
887
|
+
raise OSError(
|
|
888
|
+
f"GetInstance failed: 0x{result.extendedError & 0xFFFFFFFF:08X}"
|
|
889
|
+
)
|
|
890
|
+
return CatalogModelInstance(result.instance)
|
|
891
|
+
|
|
892
|
+
return AsyncOperation(
|
|
893
|
+
WinMLCatalogModelInfoGetInstanceWithHeadersAsync,
|
|
894
|
+
self._handle, count, keys_arr, values_arr,
|
|
895
|
+
result_fn=_extract,
|
|
896
|
+
on_complete=on_complete,
|
|
897
|
+
on_progress=on_progress,
|
|
898
|
+
)
|
|
899
|
+
|
|
900
|
+
def close(self) -> None:
|
|
901
|
+
"""Release the model info handle."""
|
|
902
|
+
if self._handle:
|
|
903
|
+
WinMLCatalogModelInfoRelease(self._handle)
|
|
904
|
+
self._handle = None
|
|
905
|
+
|
|
906
|
+
def __enter__(self) -> "CatalogModelInfo":
|
|
907
|
+
return self
|
|
908
|
+
|
|
909
|
+
def __exit__(self, *args) -> None:
|
|
910
|
+
self.close()
|
|
911
|
+
|
|
912
|
+
def __del__(self) -> None:
|
|
913
|
+
try:
|
|
914
|
+
self.close()
|
|
915
|
+
except Exception:
|
|
916
|
+
pass
|
|
917
|
+
|
|
918
|
+
def __repr__(self) -> str:
|
|
919
|
+
return f"CatalogModelInfo(name={self.name!r})"
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
# ---------------------------------------------------------------------------
|
|
923
|
+
# CatalogModelInstance
|
|
924
|
+
# ---------------------------------------------------------------------------
|
|
925
|
+
|
|
926
|
+
class CatalogModelInstance:
|
|
927
|
+
"""A downloaded or local instance of a catalog model.
|
|
928
|
+
|
|
929
|
+
Obtained from :meth:`CatalogModelInfo.get_instance_async`.
|
|
930
|
+
"""
|
|
931
|
+
|
|
932
|
+
def __init__(self, handle) -> None:
|
|
933
|
+
self._handle = handle
|
|
934
|
+
|
|
935
|
+
@property
|
|
936
|
+
def model_paths(self) -> list[str]:
|
|
937
|
+
"""List of local file paths for the model files."""
|
|
938
|
+
return _enum_strings(
|
|
939
|
+
self._handle, WinMLCatalogModelInstanceEnumModelPaths
|
|
940
|
+
)
|
|
941
|
+
|
|
942
|
+
@property
|
|
943
|
+
def model_info(self) -> CatalogModelInfo:
|
|
944
|
+
"""Get the model info associated with this instance."""
|
|
945
|
+
handle = CatalogModelInfoHandle()
|
|
946
|
+
WinMLCatalogModelInstanceGetModelInfo(self._handle, ctypes.byref(handle))
|
|
947
|
+
return CatalogModelInfo(handle)
|
|
948
|
+
|
|
949
|
+
def close(self) -> None:
|
|
950
|
+
"""Close and release the model instance."""
|
|
951
|
+
if self._handle:
|
|
952
|
+
try:
|
|
953
|
+
WinMLCatalogModelInstanceClose(self._handle)
|
|
954
|
+
except OSError:
|
|
955
|
+
pass
|
|
956
|
+
WinMLCatalogModelInstanceRelease(self._handle)
|
|
957
|
+
self._handle = None
|
|
958
|
+
|
|
959
|
+
def __enter__(self) -> "CatalogModelInstance":
|
|
960
|
+
return self
|
|
961
|
+
|
|
962
|
+
def __exit__(self, *args) -> None:
|
|
963
|
+
self.close()
|
|
964
|
+
|
|
965
|
+
def __del__(self) -> None:
|
|
966
|
+
try:
|
|
967
|
+
self.close()
|
|
968
|
+
except Exception:
|
|
969
|
+
pass
|
|
970
|
+
|
|
971
|
+
def __repr__(self) -> str:
|
|
972
|
+
paths = self.model_paths
|
|
973
|
+
return f"CatalogModelInstance(paths={paths!r})"
|