sfs-v2 0.0.1.dev1__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.
sfs/__init__.py ADDED
@@ -0,0 +1,95 @@
1
+ """SqlFileSystem Python SDK.
2
+
3
+ Only names listed in ``__all__`` are part of the stable Python-first contract.
4
+ Backend experiments live in :mod:`sfs.experimental`.
5
+ """
6
+
7
+ from .async_ import AsyncSfs, AsyncSfsScan
8
+ from .errors import (
9
+ ErrorCode,
10
+ SfsAbiMismatchError,
11
+ SfsClosedError,
12
+ SfsCorruptDataError,
13
+ SfsDatabaseError,
14
+ SfsDatabaseLockedError,
15
+ SfsError,
16
+ SfsCompatibilityError,
17
+ SfsDictionaryError,
18
+ SfsInternalError,
19
+ SfsInvalidArgumentError,
20
+ SfsIoError,
21
+ SfsNotFoundError,
22
+ SfsPreconditionError,
23
+ SfsQueueClosedError,
24
+ SfsQueueError,
25
+ SfsQueuePanicError,
26
+ SfsReadonlyError,
27
+ SfsResourceExhaustedError,
28
+ SfsUnsupportedError,
29
+ )
30
+ from .models import (
31
+ AsyncOptions,
32
+ CursorPage,
33
+ DirectoryInfo,
34
+ FileInfo,
35
+ OffsetPage,
36
+ OpenOptions,
37
+ ReadResult,
38
+ RuntimeInfo,
39
+ ScanError,
40
+ ScanErrorMode,
41
+ ScanFilter,
42
+ ScanOptions,
43
+ ScanOrder,
44
+ ScanStats,
45
+ ScannedFile,
46
+ ShrinkReport,
47
+ WriteItem,
48
+ )
49
+ from .sync import Sfs, SfsScan
50
+
51
+ __version__ = "0.0.1.dev1"
52
+
53
+ __all__ = [
54
+ "AsyncOptions",
55
+ "AsyncSfs",
56
+ "AsyncSfsScan",
57
+ "CursorPage",
58
+ "DirectoryInfo",
59
+ "ErrorCode",
60
+ "FileInfo",
61
+ "OffsetPage",
62
+ "OpenOptions",
63
+ "ReadResult",
64
+ "RuntimeInfo",
65
+ "ScanError",
66
+ "ScanErrorMode",
67
+ "ScanFilter",
68
+ "ScanOptions",
69
+ "ScanOrder",
70
+ "ScanStats",
71
+ "ScannedFile",
72
+ "Sfs",
73
+ "SfsAbiMismatchError",
74
+ "SfsClosedError",
75
+ "SfsCorruptDataError",
76
+ "SfsDatabaseError",
77
+ "SfsCompatibilityError",
78
+ "SfsDatabaseLockedError",
79
+ "SfsDictionaryError",
80
+ "SfsError",
81
+ "SfsInternalError",
82
+ "SfsInvalidArgumentError",
83
+ "SfsIoError",
84
+ "SfsNotFoundError",
85
+ "SfsPreconditionError",
86
+ "SfsQueueClosedError",
87
+ "SfsQueueError",
88
+ "SfsQueuePanicError",
89
+ "SfsReadonlyError",
90
+ "SfsResourceExhaustedError",
91
+ "SfsScan",
92
+ "SfsUnsupportedError",
93
+ "ShrinkReport",
94
+ "WriteItem",
95
+ ]
sfs/_native.py ADDED
@@ -0,0 +1,417 @@
1
+ """Private ctypes bridge. Nothing in this module is a public SDK contract."""
2
+
3
+ import ctypes
4
+ import os
5
+ import platform
6
+ import sys
7
+ import threading
8
+ from ctypes import (
9
+ POINTER,
10
+ Structure,
11
+ c_char_p,
12
+ c_int32,
13
+ c_int64,
14
+ c_size_t,
15
+ c_uint32,
16
+ c_uint64,
17
+ c_uint8,
18
+ c_void_p,
19
+ )
20
+ from typing import Optional
21
+
22
+ from .errors import ErrorCode, SfsAbiMismatchError, SfsError, error_from_native
23
+
24
+ ABI_VERSION = 2
25
+
26
+
27
+ class _SfsOpenOptionsC(Structure):
28
+ _fields_ = [
29
+ ("abi_version", c_uint32),
30
+ ("struct_size", c_uint32),
31
+ ("readonly", c_int32),
32
+ ("max_vol_size_mb", c_uint64),
33
+ ("write_flush_ms", c_uint64),
34
+ ("write_batch_max", c_size_t),
35
+ ("enable_write_queue", c_int32),
36
+ ("compression_level", c_int32),
37
+ ("enable_dict_training", c_int32),
38
+ ]
39
+
40
+
41
+ class _SfsPageC(Structure):
42
+ _fields_ = [
43
+ ("limit", c_int64),
44
+ ("offset", c_int64),
45
+ ("start", c_char_p),
46
+ ]
47
+
48
+
49
+ class _SfsFileInfoC(Structure):
50
+ _fields_ = [
51
+ ("full_path", c_char_p),
52
+ ("parent_path", c_char_p),
53
+ ("file_name", c_char_p),
54
+ ("size", c_int64),
55
+ ("storage_position", c_char_p),
56
+ ("file_uuid", c_char_p),
57
+ ("created_at", c_char_p),
58
+ ("updated_at", c_char_p),
59
+ ("is_file", c_int32),
60
+ ]
61
+
62
+
63
+ class _SfsDirInfoC(Structure):
64
+ _fields_ = [
65
+ ("file_count", c_uint64),
66
+ ("directory_count", c_uint64),
67
+ ]
68
+
69
+
70
+ class _SfsShrinkReportC(Structure):
71
+ """Legacy 24-byte report used by the required ``sfs_shrink`` symbol."""
72
+
73
+ _fields_ = [
74
+ ("volumes_scanned", c_uint64),
75
+ ("rows_deleted", c_uint64),
76
+ ("bytes_reclaimed", c_uint64),
77
+ ]
78
+
79
+
80
+ class _SfsShrinkReportV2C(Structure):
81
+ _fields_ = [
82
+ ("abi_version", c_uint32),
83
+ ("struct_size", c_uint32),
84
+ ("volumes_scanned", c_uint64),
85
+ ("rows_deleted", c_uint64),
86
+ ("bytes_reclaimed", c_uint64),
87
+ ("vacuum_failed_vols", POINTER(c_uint32)),
88
+ ("vacuum_failed_count", c_size_t),
89
+ ]
90
+
91
+
92
+ class _SfsBufferC(Structure):
93
+ _fields_ = [("data", POINTER(c_uint8)), ("len", c_size_t)]
94
+
95
+
96
+ class _SfsWriteItemC(Structure):
97
+ _fields_ = [
98
+ ("path", c_char_p),
99
+ ("data", POINTER(c_uint8)),
100
+ ("len", c_size_t),
101
+ ]
102
+
103
+
104
+ class _SfsErrorC(Structure):
105
+ _fields_ = [
106
+ ("code", c_int32),
107
+ ("message", c_char_p),
108
+ ("db_code", c_char_p),
109
+ ]
110
+
111
+
112
+ class _SfsScanFilterC(Structure):
113
+ _fields_ = [
114
+ ("path_prefix", c_char_p),
115
+ ("extensions", POINTER(c_char_p)),
116
+ ("n_extensions", c_size_t),
117
+ ("name_like", c_char_p),
118
+ ("name_prefix", c_char_p),
119
+ ("name_suffix", c_char_p),
120
+ ("has_size_range", c_int32),
121
+ ("size_min", c_int64),
122
+ ("size_max", c_int64),
123
+ ("updated_after", c_char_p),
124
+ ("updated_before", c_char_p),
125
+ ]
126
+
127
+
128
+ class _SfsScanOptionsC(Structure):
129
+ _fields_ = [
130
+ ("filter", _SfsScanFilterC),
131
+ ("order", c_int32),
132
+ ("batch_size", c_size_t),
133
+ ("error_mode", c_int32),
134
+ ]
135
+
136
+
137
+ class _SfsScanErrorC(Structure):
138
+ _fields_ = [
139
+ ("code", c_int32),
140
+ ("path", c_char_p),
141
+ ("message", c_char_p),
142
+ ]
143
+
144
+
145
+ class _SfsAbiInfoC(Structure):
146
+ _fields_ = [
147
+ ("abi_version", c_uint32),
148
+ ("struct_size", c_uint32),
149
+ ("open_options_size", c_size_t),
150
+ ("page_size", c_size_t),
151
+ ("file_info_size", c_size_t),
152
+ ("dir_info_size", c_size_t),
153
+ ("shrink_report_size", c_size_t),
154
+ ("buffer_size", c_size_t),
155
+ ("write_item_size", c_size_t),
156
+ ("error_size", c_size_t),
157
+ ("scan_filter_size", c_size_t),
158
+ ("scan_options_size", c_size_t),
159
+ ("scan_error_size", c_size_t),
160
+ ]
161
+
162
+
163
+ def encode_text(value: str, field: str) -> bytes:
164
+ if not isinstance(value, str):
165
+ raise TypeError("%s must be str" % field)
166
+ if type(value) is not str:
167
+ value = str.__str__(value)
168
+ if "\x00" in value:
169
+ raise ValueError("%s cannot contain NUL" % field)
170
+ return value.encode("utf-8")
171
+
172
+
173
+ def decode_text(value: Optional[bytes]) -> Optional[str]:
174
+ return value.decode("utf-8") if value else None
175
+
176
+
177
+ def _platform_directory() -> str:
178
+ platform_name = {"win32": "win32", "linux": "linux", "darwin": "darwin"}.get(sys.platform)
179
+ machine = platform.machine().lower()
180
+ arch = {"x86_64": "x86_64", "amd64": "x86_64", "arm64": "aarch64", "aarch64": "aarch64"}.get(machine)
181
+ if not platform_name or not arch:
182
+ raise RuntimeError("Unsupported platform: %s-%s" % (sys.platform, machine))
183
+ return "%s-%s" % (platform_name, arch)
184
+
185
+
186
+ def _library_name() -> str:
187
+ if sys.platform == "win32":
188
+ return "sfs_ffi.dll"
189
+ if sys.platform == "darwin":
190
+ return "libsfs_ffi.dylib"
191
+ return "libsfs_ffi.so"
192
+
193
+
194
+ def _library_path() -> str:
195
+ configured = os.environ.get("SFS_NATIVE_PATH")
196
+ if configured:
197
+ return configured
198
+ package_native = os.path.join(os.path.dirname(__file__), "native", _platform_directory(), _library_name())
199
+ if os.path.exists(package_native):
200
+ return package_native
201
+ legacy_native = os.path.join(os.path.dirname(os.path.dirname(__file__)), "native", _platform_directory(), _library_name())
202
+ return legacy_native
203
+
204
+
205
+ class _NativeApi:
206
+ def __init__(self) -> None:
207
+ try:
208
+ self.lib = ctypes.CDLL(_library_path())
209
+ except OSError as exc:
210
+ raise RuntimeError("Unable to load sfs native library: %s" % exc) from exc
211
+ self._bind()
212
+ self.abi_info = self._verify_abi()
213
+
214
+ def _bind(self) -> None:
215
+ lib = self.lib
216
+ required_symbols = (
217
+ "sfs_abi_version", "sfs_get_abi_info", "sfs_open",
218
+ "sfs_open_postgres", "sfs_open_mysql", "sfs_open_remote",
219
+ "sfs_close_checked", "sfs_stat", "sfs_exists_file",
220
+ "sfs_exists_dir", "sfs_list", "sfs_dir_info", "sfs_fs_info",
221
+ "sfs_read", "sfs_read_batch", "sfs_write", "sfs_write_batch",
222
+ "sfs_scan_open", "sfs_scan_next", "sfs_scan_take_errors",
223
+ "sfs_scan_counts", "sfs_scan_close", "sfs_mkdir", "sfs_delete",
224
+ "sfs_rename", "sfs_shrink", "sfs_free_buffer",
225
+ "sfs_free_buffers", "sfs_free_file_infos",
226
+ "sfs_free_scan_errors", "sfs_error_free",
227
+ )
228
+ missing = [name for name in required_symbols if not hasattr(lib, name)]
229
+ if missing:
230
+ raise SfsAbiMismatchError(
231
+ "native library is missing ABI v2 symbols: " + ", ".join(missing)
232
+ )
233
+ try:
234
+ lib.sfs_abi_version.restype = c_uint32
235
+ lib.sfs_abi_version.argtypes = []
236
+ lib.sfs_get_abi_info.restype = c_int32
237
+ lib.sfs_get_abi_info.argtypes = [POINTER(_SfsAbiInfoC), c_size_t]
238
+ except AttributeError as exc:
239
+ raise SfsAbiMismatchError("native library does not expose the SFS ABI v2 handshake") from exc
240
+
241
+ lib.sfs_open.restype = c_void_p
242
+ lib.sfs_open.argtypes = [c_char_p, POINTER(_SfsOpenOptionsC), POINTER(POINTER(_SfsErrorC))]
243
+ lib.sfs_open_postgres.restype = c_void_p
244
+ lib.sfs_open_postgres.argtypes = [c_char_p, POINTER(_SfsOpenOptionsC), POINTER(POINTER(_SfsErrorC))]
245
+ lib.sfs_open_mysql.restype = c_void_p
246
+ lib.sfs_open_mysql.argtypes = [c_char_p, POINTER(_SfsOpenOptionsC), POINTER(POINTER(_SfsErrorC))]
247
+ lib.sfs_open_remote.restype = c_void_p
248
+ lib.sfs_open_remote.argtypes = [c_char_p, POINTER(POINTER(_SfsErrorC))]
249
+
250
+ # These capabilities were added after the initial ABI v2 release. Keep
251
+ # them optional at load time so the stable local SQLite surface can
252
+ # still diagnose/use an early ABI v2 library. Call sites must handle
253
+ # absence explicitly: token auth reports UNSUPPORTED, while shrink v2
254
+ # deliberately falls back to the documented legacy 24-byte report.
255
+ open_remote_with_token = getattr(lib, "sfs_open_remote_with_token", None)
256
+ if open_remote_with_token is not None:
257
+ open_remote_with_token.restype = c_void_p
258
+ open_remote_with_token.argtypes = [
259
+ c_char_p,
260
+ c_char_p,
261
+ POINTER(POINTER(_SfsErrorC)),
262
+ ]
263
+ stream_flush = getattr(lib, "sfs_stream_flush", None)
264
+ if stream_flush is not None:
265
+ stream_flush.restype = c_int32
266
+ stream_flush.argtypes = [c_void_p, POINTER(POINTER(_SfsErrorC))]
267
+ shrink_report_v2_size = getattr(lib, "sfs_shrink_report_v2_size", None)
268
+ shrink_v2 = getattr(lib, "sfs_shrink_v2", None)
269
+ free_u32_array = getattr(lib, "sfs_free_u32_array", None)
270
+ shrink_capabilities = (shrink_report_v2_size, shrink_v2, free_u32_array)
271
+ if not all(capability is not None for capability in shrink_capabilities):
272
+ # Optional extensions are atomic capabilities, not base-ABI requirements. A mixed
273
+ # deployment may briefly expose only part of the trio; disable v2 and retain the
274
+ # required legacy sfs_shrink path rather than making the entire SDK unloadable.
275
+ shrink_report_v2_size = None
276
+ shrink_v2 = None
277
+ free_u32_array = None
278
+ if shrink_v2 is not None:
279
+ shrink_report_v2_size.restype = c_size_t
280
+ shrink_report_v2_size.argtypes = []
281
+ shrink_v2.restype = c_int32
282
+ shrink_v2.argtypes = [
283
+ c_void_p,
284
+ POINTER(_SfsShrinkReportV2C),
285
+ c_size_t,
286
+ POINTER(POINTER(_SfsErrorC)),
287
+ ]
288
+ free_u32_array.restype = None
289
+ free_u32_array.argtypes = [POINTER(c_uint32), c_size_t]
290
+
291
+ lib.sfs_close_checked.restype = c_int32
292
+ lib.sfs_close_checked.argtypes = [c_void_p, POINTER(POINTER(_SfsErrorC))]
293
+
294
+ lib.sfs_stat.restype = c_int32
295
+ lib.sfs_stat.argtypes = [c_void_p, c_char_p, POINTER(POINTER(_SfsFileInfoC)), POINTER(POINTER(_SfsErrorC))]
296
+ lib.sfs_exists_file.restype = c_int32
297
+ lib.sfs_exists_file.argtypes = [c_void_p, c_char_p, POINTER(POINTER(_SfsErrorC))]
298
+ lib.sfs_exists_dir.restype = c_int32
299
+ lib.sfs_exists_dir.argtypes = [c_void_p, c_char_p, POINTER(POINTER(_SfsErrorC))]
300
+ lib.sfs_list.restype = c_int32
301
+ lib.sfs_list.argtypes = [c_void_p, c_char_p, POINTER(_SfsPageC), c_char_p, c_int32, POINTER(POINTER(_SfsFileInfoC)), POINTER(c_size_t), POINTER(POINTER(_SfsErrorC))]
302
+ lib.sfs_dir_info.restype = c_int32
303
+ lib.sfs_dir_info.argtypes = [c_void_p, c_char_p, POINTER(_SfsDirInfoC), POINTER(POINTER(_SfsErrorC))]
304
+ lib.sfs_fs_info.restype = c_int32
305
+ lib.sfs_fs_info.argtypes = [c_void_p, POINTER(_SfsDirInfoC), POINTER(POINTER(_SfsErrorC))]
306
+
307
+ lib.sfs_read.restype = c_int32
308
+ lib.sfs_read.argtypes = [c_void_p, c_char_p, POINTER(POINTER(c_uint8)), POINTER(c_size_t), POINTER(POINTER(_SfsErrorC))]
309
+ lib.sfs_read_batch.restype = c_int32
310
+ lib.sfs_read_batch.argtypes = [c_void_p, POINTER(c_char_p), c_size_t, POINTER(POINTER(_SfsBufferC)), POINTER(POINTER(_SfsErrorC))]
311
+ lib.sfs_write.restype = c_int32
312
+ lib.sfs_write.argtypes = [c_void_p, c_char_p, POINTER(c_uint8), c_size_t, POINTER(POINTER(_SfsErrorC))]
313
+ lib.sfs_write_batch.restype = c_int32
314
+ lib.sfs_write_batch.argtypes = [c_void_p, POINTER(_SfsWriteItemC), c_size_t, POINTER(POINTER(_SfsErrorC))]
315
+
316
+ lib.sfs_scan_open.restype = c_void_p
317
+ lib.sfs_scan_open.argtypes = [c_void_p, POINTER(_SfsScanOptionsC), POINTER(POINTER(_SfsErrorC))]
318
+ lib.sfs_scan_next.restype = c_int32
319
+ lib.sfs_scan_next.argtypes = [c_void_p, POINTER(POINTER(_SfsFileInfoC)), POINTER(POINTER(c_uint8)), POINTER(c_size_t), POINTER(POINTER(_SfsErrorC))]
320
+ lib.sfs_scan_take_errors.restype = c_int32
321
+ lib.sfs_scan_take_errors.argtypes = [c_void_p, POINTER(POINTER(_SfsScanErrorC)), POINTER(c_size_t), POINTER(POINTER(_SfsErrorC))]
322
+ lib.sfs_scan_counts.restype = None
323
+ lib.sfs_scan_counts.argtypes = [c_void_p, POINTER(c_uint64), POINTER(c_uint64), POINTER(c_uint64)]
324
+ lib.sfs_scan_close.restype = None
325
+ lib.sfs_scan_close.argtypes = [c_void_p]
326
+
327
+ lib.sfs_mkdir.restype = c_int32
328
+ lib.sfs_mkdir.argtypes = [c_void_p, c_char_p, POINTER(POINTER(_SfsErrorC))]
329
+ lib.sfs_delete.restype = c_int32
330
+ lib.sfs_delete.argtypes = [c_void_p, c_char_p, c_int32, POINTER(POINTER(_SfsErrorC))]
331
+ lib.sfs_rename.restype = c_int32
332
+ lib.sfs_rename.argtypes = [c_void_p, c_char_p, c_char_p, POINTER(POINTER(_SfsErrorC))]
333
+ lib.sfs_shrink.restype = c_int32
334
+ lib.sfs_shrink.argtypes = [c_void_p, POINTER(_SfsShrinkReportC), POINTER(POINTER(_SfsErrorC))]
335
+
336
+ lib.sfs_free_buffer.restype = None
337
+ lib.sfs_free_buffer.argtypes = [POINTER(c_uint8), c_size_t]
338
+ lib.sfs_free_buffers.restype = None
339
+ lib.sfs_free_buffers.argtypes = [POINTER(_SfsBufferC), c_size_t]
340
+ lib.sfs_free_file_infos.restype = None
341
+ lib.sfs_free_file_infos.argtypes = [POINTER(_SfsFileInfoC), c_size_t]
342
+ lib.sfs_free_scan_errors.restype = None
343
+ lib.sfs_free_scan_errors.argtypes = [POINTER(_SfsScanErrorC), c_size_t]
344
+ lib.sfs_error_free.restype = None
345
+ lib.sfs_error_free.argtypes = [POINTER(_SfsErrorC)]
346
+
347
+ def _verify_abi(self) -> _SfsAbiInfoC:
348
+ version = int(self.lib.sfs_abi_version())
349
+ if version != ABI_VERSION:
350
+ raise SfsAbiMismatchError("native ABI version %d does not match Python SDK ABI %d" % (version, ABI_VERSION))
351
+ info = _SfsAbiInfoC()
352
+ code = int(self.lib.sfs_get_abi_info(ctypes.byref(info), ctypes.sizeof(info)))
353
+ if code != 0:
354
+ raise SfsAbiMismatchError("native library rejected ABI info request with code %d" % code)
355
+ if int(info.abi_version) != ABI_VERSION:
356
+ raise SfsAbiMismatchError(
357
+ "ABI info version %d does not match Python SDK ABI %d"
358
+ % (int(info.abi_version), ABI_VERSION)
359
+ )
360
+ if int(info.struct_size) < ctypes.sizeof(_SfsAbiInfoC):
361
+ raise SfsAbiMismatchError(
362
+ "ABI info struct is too small: native=%d python=%d"
363
+ % (int(info.struct_size), ctypes.sizeof(_SfsAbiInfoC))
364
+ )
365
+ expected = {
366
+ "open_options_size": ctypes.sizeof(_SfsOpenOptionsC),
367
+ "page_size": ctypes.sizeof(_SfsPageC),
368
+ "file_info_size": ctypes.sizeof(_SfsFileInfoC),
369
+ "dir_info_size": ctypes.sizeof(_SfsDirInfoC),
370
+ "shrink_report_size": ctypes.sizeof(_SfsShrinkReportC),
371
+ "buffer_size": ctypes.sizeof(_SfsBufferC),
372
+ "write_item_size": ctypes.sizeof(_SfsWriteItemC),
373
+ "error_size": ctypes.sizeof(_SfsErrorC),
374
+ "scan_filter_size": ctypes.sizeof(_SfsScanFilterC),
375
+ "scan_options_size": ctypes.sizeof(_SfsScanOptionsC),
376
+ "scan_error_size": ctypes.sizeof(_SfsScanErrorC),
377
+ }
378
+ mismatches = ["%s python=%d native=%d" % (name, size, int(getattr(info, name))) for name, size in expected.items() if int(getattr(info, name)) != size]
379
+ if mismatches:
380
+ raise SfsAbiMismatchError("native ABI layout mismatch: " + "; ".join(mismatches))
381
+ return info
382
+
383
+ def check_error(
384
+ self,
385
+ code: int,
386
+ err_ref: POINTER(_SfsErrorC),
387
+ *,
388
+ operation: Optional[str] = None,
389
+ path: Optional[str] = None,
390
+ ) -> None:
391
+ if code == 0:
392
+ return
393
+ raw_code = code
394
+ message = "Unknown native error (code=%d)" % code
395
+ database_code = None
396
+ if bool(err_ref):
397
+ try:
398
+ error = err_ref.contents
399
+ raw_code = int(error.code)
400
+ message = error.message.decode("utf-8") if error.message else message
401
+ database_code = error.db_code.decode("utf-8") if error.db_code else None
402
+ finally:
403
+ self.lib.sfs_error_free(err_ref)
404
+ raise error_from_native(raw_code, message, operation=operation, path=path, database_code=database_code)
405
+
406
+
407
+ _native_lock = threading.Lock()
408
+ _native_instance: Optional[_NativeApi] = None
409
+
410
+
411
+ def get_native() -> _NativeApi:
412
+ global _native_instance
413
+ if _native_instance is None:
414
+ with _native_lock:
415
+ if _native_instance is None:
416
+ _native_instance = _NativeApi()
417
+ return _native_instance