spark-cell-runner 0.7.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.
@@ -0,0 +1,10 @@
1
+ """spark-cell-runner — headless engine for Databricks notebook cells and SQL.
2
+
3
+ Runs Databricks notebook-source .py cells and SQL against Databricks
4
+ (Databricks Connect) or a local Sail Spark pool, with Unity Catalog sync and
5
+ a local Delta / Iceberg warehouse. The VS Code extension of the same name
6
+ ships these same modules and spawns them by path; this package is the
7
+ pip-installable CLI form.
8
+ """
9
+
10
+ __version__ = "0.7.0"
@@ -0,0 +1,536 @@
1
+ # Databricks notebook source
2
+
3
+ import builtins
4
+ import os
5
+ import re
6
+ import shlex
7
+ import shutil
8
+ import io
9
+ import types
10
+ from pathlib import Path
11
+ _dcr_workspace_path_mappings = globals().get("_dcr_workspace_path_mappings", {})
12
+ _dcr_secret_values = globals().get("_dcr_secret_values", {})
13
+ _dcr_widget_values = globals().get("_dcr_widget_values", {})
14
+ class DCRNotebookExit(Exception):
15
+ pass
16
+ def log_appinsights(*args, **kwargs):
17
+ message = kwargs.get("message") if isinstance(kwargs, dict) else None
18
+ if message is None and args:
19
+ message = args[0]
20
+ print(f"[spark-cell-runner] log_appinsights fallback: {message}")
21
+ def log_info(message, properties=None):
22
+ print(f"[spark-cell-runner] log_info: {message}")
23
+ def log_warning(message, properties=None):
24
+ print(f"[spark-cell-runner] log_warning: {message}")
25
+ def log_error(message, properties=None):
26
+ print(f"[spark-cell-runner] log_error: {message}")
27
+ def log_metric(name, value, properties=None):
28
+ print(f"[spark-cell-runner] log_metric: {name}={value}")
29
+ def display(*args, **kwargs):
30
+ if not args:
31
+ return None
32
+ obj = args[0]
33
+ show = getattr(obj, "show", None)
34
+ if callable(show):
35
+ try:
36
+ return show(20, truncate=False)
37
+ except TypeError:
38
+ return show()
39
+ to_string = getattr(obj, "to_string", None)
40
+ if callable(to_string):
41
+ print(to_string())
42
+ return None
43
+ print(obj)
44
+ return None
45
+ def displayHTML(html=""):
46
+ print(html)
47
+ for __dcr_df_module in ("pyspark.sql.connect.dataframe", "pyspark.sql.dataframe"):
48
+ try:
49
+ __dcr_df_mod = __import__(__dcr_df_module, fromlist=["DataFrame"])
50
+ __dcr_df_cls = getattr(__dcr_df_mod, "DataFrame", None)
51
+ if __dcr_df_cls is not None and not hasattr(__dcr_df_cls, "display"):
52
+ __dcr_df_cls.display = lambda self, *a, **k: display(self)
53
+ except Exception:
54
+ pass
55
+ def __dcr_safe_callable(fn, name):
56
+ if not callable(fn):
57
+ return fn
58
+ if getattr(fn, "__dcr_safe_wrapper__", False):
59
+ return fn
60
+ def _wrapped(*args, **kwargs):
61
+ try:
62
+ return fn(*args, **kwargs)
63
+ except Exception as exc:
64
+ print(f"[spark-cell-runner] {name} failed: {exc}")
65
+ return None
66
+ _wrapped.__dcr_safe_wrapper__ = True
67
+ return _wrapped
68
+ def __dcr_wrap_logging_helpers():
69
+ for _name in ["log_appinsights", "log_info", "log_warning", "log_error", "log_metric"]:
70
+ if _name in globals():
71
+ globals()[_name] = __dcr_safe_callable(globals()[_name], _name)
72
+ def __dcr_wrap_hello__config_reader():
73
+ reader_cls = globals().get("AladdinConfigReader")
74
+ if reader_cls is None:
75
+ return
76
+ original = getattr(reader_cls, "get_config_variables", None)
77
+ if not callable(original) or getattr(original, "__dcr_safe_wrapper__", False):
78
+ return
79
+ def _wrapped(self, hello__file_id):
80
+ result = original(self, hello__file_id)
81
+ if result is not None:
82
+ return result
83
+ try:
84
+ full_table_name = getattr(self, "full_table_name", f"{getattr(self, 'catalog_name', '')}.{getattr(self, 'schema_name', 'common')}")
85
+ row = spark.sql(f"SELECT * from table1").collect()
86
+ if not row:
87
+ return None
88
+ row = row[0]
89
+ file_info = {
90
+ "config_path": row["ConfigPath"],
91
+ }
92
+ app_path = globals().get("app_storage_path", "")
93
+ full_config_path = f"{app_path.rstrip('/')}/{file_info['config_path'].lstrip('/')}"
94
+ except Exception as exc:
95
+ print(f"[spark-cell-runner] Aladdin config fallback failed: {exc}")
96
+ return None
97
+
98
+ try:
99
+ json_content = dbutils.fs.head(full_config_path)
100
+ except Exception:
101
+ json_content = dcr_read_text_via_spark(full_config_path)
102
+
103
+ # NOTE: the original hardcoded bootstrap ended here mid-function; _wrapped is
104
+ # intentionally left unattached until the Aladdin fallback is finished.
105
+ return None
106
+ def dcr_translate_workspace_path(value):
107
+ if not isinstance(value, str):
108
+ return value
109
+ normalized = value.replace("\\", "/")
110
+ for source_prefix, target_prefix in sorted(_dcr_workspace_path_mappings.items(), key=lambda item: len(item[0]), reverse=True):
111
+ source_norm = source_prefix.replace("\\", "/")
112
+ if normalized == source_norm or normalized.startswith(source_norm + "/"):
113
+ suffix = normalized[len(source_norm):].lstrip("/")
114
+ translated = os.path.join(target_prefix, *([part for part in suffix.split("/") if part] if suffix else []))
115
+ return translated
116
+ return value
117
+ def dcr_list_mapped_library_entries(translated):
118
+ if isinstance(translated, str) and translated.lower().endswith(".txt") and dcr_original_isfile(translated):
119
+ entries = []
120
+ with dcr_original_open(translated, "r", encoding="utf-8") as handle:
121
+ for raw_line in handle:
122
+ line = raw_line.strip()
123
+ if not line or line.startswith("#"):
124
+ continue
125
+ entries.append(line.split("=", 1)[0].strip())
126
+ return entries
127
+ return None
128
+ def dcr_wheel_to_requirement(token):
129
+ basename = os.path.basename(token)
130
+ match = re.match(r"(?P<name>.+?)-(?P<version>\d[^-]*)-", basename)
131
+ if match:
132
+ return f"{match.group('name')}=={match.group('version')}"
133
+ stem = re.sub(r"\.(whl|egg)$", "", basename, flags=re.IGNORECASE)
134
+ return stem
135
+ def dcr_translate_pip_command(command):
136
+ args = shlex.split(command)
137
+ translated_args = []
138
+ for arg in args:
139
+ translated = dcr_translate_workspace_path(arg)
140
+ if isinstance(arg, str) and arg.startswith("/Volumes/") and not os.path.exists(translated):
141
+ lowered = arg.lower()
142
+ if lowered.endswith(".whl") or lowered.endswith(".egg"):
143
+ translated_args.append(dcr_wheel_to_requirement(arg))
144
+ continue
145
+ translated_args.append(translated)
146
+ return translated_args
147
+ def dcr_read_text_via_spark(path_value, max_bytes=65536):
148
+ spark_session = globals().get("spark")
149
+ if spark_session is None:
150
+ raise FileNotFoundError(path_value)
151
+ rows = spark_session.read.text(path_value).collect()
152
+ text_value = "\n".join([row[0] for row in rows])
153
+ return text_value[:max_bytes]
154
+ def dcr_path_is_abfss(path_value):
155
+ return isinstance(path_value, str) and path_value.startswith("abfss://")
156
+ def dcr_list_via_spark(path_value):
157
+ spark_session = globals().get("spark")
158
+ if spark_session is None:
159
+ raise FileNotFoundError(path_value)
160
+ rows = spark_session.read.format("binaryFile").load(path_value.rstrip("/") + "/*").select("path").collect()
161
+ items = []
162
+ for row in rows:
163
+ item_path = row[0]
164
+ name = item_path.rsplit("/", 1)[-1]
165
+ items.append(DcrFileInfo(item_path, name, False))
166
+ return items
167
+ def dcr_write_text_via_spark(path_value, text_value):
168
+ spark_session = globals().get("spark")
169
+ if spark_session is None:
170
+ raise FileNotFoundError(path_value)
171
+ spark_session.createDataFrame([(text_value,)], ["value"]).coalesce(1).write.mode("overwrite").text(path_value)
172
+ return True
173
+ def dcr_rm_via_spark(path_value, recurse=False):
174
+ spark_session = globals().get("spark")
175
+ if spark_session is None:
176
+ raise FileNotFoundError(path_value)
177
+ sc = getattr(spark_session, "sparkContext", None)
178
+ jvm = getattr(sc, "_jvm", None) or getattr(spark_session, "_jvm", None)
179
+ if jvm is None or sc is None:
180
+ raise RuntimeError("JVM access unavailable for external rm")
181
+ hadoop_path = jvm.org.apache.hadoop.fs.Path(path_value)
182
+ hadoop_conf = sc._jsc.hadoopConfiguration()
183
+ fs = hadoop_path.getFileSystem(hadoop_conf)
184
+ return bool(fs.delete(hadoop_path, bool(recurse)))
185
+ dcr_original_open = getattr(builtins, "__dcr_original_open", builtins.open)
186
+ builtins.__dcr_original_open = dcr_original_open
187
+ def dcr_is_databricks_path(path_value):
188
+ if not isinstance(path_value, str):
189
+ return False
190
+ return (
191
+ path_value.startswith("/Volumes/")
192
+ or path_value.startswith("/dbfs/")
193
+ or path_value.startswith("dbfs:/")
194
+ or path_value.startswith("abfss://")
195
+ )
196
+ def dcr_read_binary_via_spark(path_value):
197
+ spark_session = globals().get("spark")
198
+ if spark_session is None:
199
+ raise FileNotFoundError(path_value)
200
+ rows = spark_session.read.format("binaryFile").load(path_value).select("content").collect()
201
+ if not rows:
202
+ raise FileNotFoundError(path_value)
203
+ return rows[0][0]
204
+ class DcrRawStream(io.RawIOBase):
205
+ def __init__(self, source):
206
+ self._source = source
207
+ def readable(self):
208
+ return True
209
+ def readinto(self, buffer):
210
+ chunk = self._source.read(len(buffer))
211
+ if not chunk:
212
+ return 0
213
+ count = len(chunk)
214
+ buffer[:count] = chunk
215
+ return count
216
+ def close(self):
217
+ try:
218
+ self._source.close()
219
+ except Exception:
220
+ pass
221
+ super().close()
222
+ def dcr_open_databricks_stream(path_value, mode, kwargs):
223
+ raw_source = None
224
+ if path_value.startswith("/Volumes/"):
225
+ try:
226
+ from databricks.sdk import WorkspaceClient
227
+ client = globals().get("__dcr_workspace_client")
228
+ if client is None:
229
+ client = WorkspaceClient()
230
+ globals()["__dcr_workspace_client"] = client
231
+ raw_source = client.files.download(path_value).contents
232
+ except Exception:
233
+ raw_source = None
234
+ if raw_source is not None:
235
+ buffered = io.BufferedReader(DcrRawStream(raw_source))
236
+ else:
237
+ buffered = io.BytesIO(dcr_read_binary_via_spark(path_value))
238
+ if isinstance(mode, str) and "b" in mode:
239
+ return buffered
240
+ return io.TextIOWrapper(
241
+ buffered,
242
+ encoding=kwargs.get("encoding") or "utf-8",
243
+ errors=kwargs.get("errors"),
244
+ newline=kwargs.get("newline"),
245
+ )
246
+ def __dcr_open(file, *args, **kwargs):
247
+ translated = dcr_translate_workspace_path(file)
248
+ mode = args[0] if args else kwargs.get("mode", "r")
249
+ is_read = not isinstance(mode, str) or ("w" not in mode and "a" not in mode and "x" not in mode and "+" not in mode)
250
+ if is_read and dcr_is_databricks_path(translated) and not dcr_original_exists(translated):
251
+ try:
252
+ return dcr_open_databricks_stream(translated, mode, kwargs)
253
+ except Exception as exc:
254
+ print(f"[spark-cell-runner] could not read Databricks path {translated}: {exc}")
255
+ return dcr_original_open(translated, *args, **kwargs)
256
+ builtins.open = __dcr_open
257
+ dcr_original_exists = getattr(os.path, "__dcr_original_exists", os.path.exists)
258
+ os.path.__dcr_original_exists = dcr_original_exists
259
+ os.path.exists = lambda value: dcr_original_exists(dcr_translate_workspace_path(value))
260
+ dcr_original_isfile = getattr(os.path, "__dcr_original_isfile", os.path.isfile)
261
+ os.path.__dcr_original_isfile = dcr_original_isfile
262
+ os.path.isfile = lambda value: dcr_original_isfile(dcr_translate_workspace_path(value))
263
+ dcr_original_isdir = getattr(os.path, "__dcr_original_isdir", os.path.isdir)
264
+ os.path.__dcr_original_isdir = dcr_original_isdir
265
+ os.path.isdir = lambda value: (dcr_list_mapped_library_entries(dcr_translate_workspace_path(value)) is not None) or dcr_original_isdir(dcr_translate_workspace_path(value))
266
+ dcr_original_listdir = getattr(os, "__dcr_original_listdir", os.listdir)
267
+ os.__dcr_original_listdir = dcr_original_listdir
268
+ os.listdir = lambda value: (dcr_list_mapped_library_entries(dcr_translate_workspace_path(value)) if dcr_list_mapped_library_entries(dcr_translate_workspace_path(value)) is not None else dcr_original_listdir(dcr_translate_workspace_path(value)))
269
+ dcr_original_path_open = getattr(Path, "__dcr_original_path_open", Path.open)
270
+ Path.__dcr_original_path_open = dcr_original_path_open
271
+ def __dcr_path_open(self, *args, **kwargs):
272
+ return dcr_original_path_open(self, *args, **kwargs)
273
+ Path.open = __dcr_path_open
274
+ class DcrFileInfo:
275
+ def __init__(self, path_value, name, is_dir=False, size=0):
276
+ self.path = path_value
277
+ self.name = name
278
+ self.size = size
279
+ self._is_dir = bool(is_dir)
280
+ def isDir(self):
281
+ return self._is_dir
282
+ def isFile(self):
283
+ return not self._is_dir
284
+ @classmethod
285
+ def from_entry(cls, entry):
286
+ if isinstance(entry, cls):
287
+ return entry
288
+ path_value = getattr(entry, "path", None) or getattr(entry, "file_path", None) or ""
289
+ name = getattr(entry, "name", None) or (path_value.rstrip("/").rsplit("/", 1)[-1] if path_value else "")
290
+ size = getattr(entry, "size", 0)
291
+ is_dir = getattr(entry, "_is_dir", None)
292
+ if is_dir is None and hasattr(entry, "isDir"):
293
+ try:
294
+ candidate = getattr(entry, "isDir")
295
+ is_dir = candidate() if callable(candidate) else candidate
296
+ except Exception:
297
+ is_dir = None
298
+ if is_dir is None and hasattr(entry, "is_dir"):
299
+ try:
300
+ candidate = getattr(entry, "is_dir")
301
+ is_dir = candidate() if callable(candidate) else candidate
302
+ except Exception:
303
+ is_dir = None
304
+ if is_dir is None and path_value:
305
+ translated = dcr_translate_workspace_path(path_value)
306
+ is_dir = os.path.isdir(translated)
307
+ return cls(path_value, name, bool(is_dir), size)
308
+ def __repr__(self):
309
+ return f"DcrFileInfo(path={self.path!r}, name={self.name!r}, is_dir={self._is_dir!r}, size={self.size!r})"
310
+ class DcrFsProxy:
311
+ def __init__(self, wrapped):
312
+ self._wrapped = wrapped
313
+ def ls(self, value):
314
+ translated = dcr_translate_workspace_path(value)
315
+ mapped = dcr_list_mapped_library_entries(translated)
316
+ if mapped is not None:
317
+ return [DcrFileInfo(f"{str(value).rstrip('/')}/{name}", name, os.path.isdir(os.path.join(translated, name)), os.path.getsize(os.path.join(translated, name)) if os.path.isfile(os.path.join(translated, name)) else 0) for name in mapped]
318
+ if dcr_path_is_abfss(value):
319
+ return dcr_list_via_spark(value)
320
+ if os.path.isdir(translated):
321
+ return [DcrFileInfo(f"{str(value).rstrip('/')}/{name}", name, os.path.isdir(os.path.join(translated, name)), os.path.getsize(os.path.join(translated, name)) if os.path.isfile(os.path.join(translated, name)) else 0) for name in os.listdir(translated)]
322
+ if self._wrapped is not None:
323
+ return [DcrFileInfo.from_entry(entry) for entry in self._wrapped.fs.ls(value)]
324
+ raise FileNotFoundError(translated)
325
+ def head(self, value, max_bytes=65536):
326
+ translated = dcr_translate_workspace_path(value)
327
+ if isinstance(value, str) and value.startswith("abfss://"):
328
+ try:
329
+ return dcr_read_text_via_spark(value, max_bytes)
330
+ except Exception:
331
+ pass
332
+ if dcr_original_isfile(translated):
333
+ with dcr_original_open(translated, "r", encoding="utf-8") as handle:
334
+ return handle.read(max_bytes)
335
+ if self._wrapped is not None:
336
+ return self._wrapped.fs.head(value, max_bytes)
337
+ raise FileNotFoundError(translated)
338
+ def mkdirs(self, value):
339
+ if dcr_path_is_abfss(value):
340
+ return True
341
+ os.makedirs(dcr_translate_workspace_path(value), exist_ok=True)
342
+ return True
343
+ def put(self, value, contents, overwrite=False):
344
+ if dcr_path_is_abfss(value):
345
+ return dcr_write_text_via_spark(value, contents)
346
+ translated = dcr_translate_workspace_path(value)
347
+ parent = os.path.dirname(translated)
348
+ if parent:
349
+ os.makedirs(parent, exist_ok=True)
350
+ if not overwrite and os.path.exists(translated):
351
+ raise FileExistsError(translated)
352
+ with dcr_original_open(translated, "w", encoding="utf-8") as handle:
353
+ handle.write(contents)
354
+ return True
355
+ def mv(self, src, dst, recurse=False):
356
+ if (dcr_path_is_abfss(src) or dcr_path_is_abfss(dst)) and self._wrapped is not None:
357
+ return self._wrapped.fs.mv(src, dst, recurse)
358
+ translated_src = dcr_translate_workspace_path(src)
359
+ translated_dst = dcr_translate_workspace_path(dst)
360
+ parent = os.path.dirname(translated_dst)
361
+ if parent:
362
+ os.makedirs(parent, exist_ok=True)
363
+ shutil.move(translated_src, translated_dst)
364
+ return True
365
+ def rm(self, value, recurse=False):
366
+ if dcr_path_is_abfss(value):
367
+ try:
368
+ return dcr_rm_via_spark(value, recurse)
369
+ except Exception as exc:
370
+ if self._wrapped is not None:
371
+ try:
372
+ return self._wrapped.fs.rm(value, recurse)
373
+ except Exception:
374
+ pass
375
+ print("[spark-cell-runner] Skipping rm for external path %r (%s)" % (value, exc))
376
+ return True
377
+ translated = dcr_translate_workspace_path(value)
378
+ if os.path.isdir(translated):
379
+ shutil.rmtree(translated, ignore_errors=recurse)
380
+ elif os.path.exists(translated):
381
+ os.remove(translated)
382
+ return True
383
+ def cp(self, src, dst, recurse=False):
384
+ if (dcr_path_is_abfss(src) or dcr_path_is_abfss(dst)) and self._wrapped is not None:
385
+ return self._wrapped.fs.cp(src, dst, recurse)
386
+ translated_src = dcr_translate_workspace_path(src)
387
+ translated_dst = dcr_translate_workspace_path(dst)
388
+ parent = os.path.dirname(translated_dst)
389
+ if parent:
390
+ os.makedirs(parent, exist_ok=True)
391
+ if os.path.isdir(translated_src):
392
+ shutil.copytree(translated_src, translated_dst, dirs_exist_ok=True)
393
+ else:
394
+ shutil.copy2(translated_src, translated_dst)
395
+ return True
396
+ def __getattr__(self, name):
397
+ if self._wrapped is None:
398
+ raise AttributeError(name)
399
+ return getattr(self._wrapped.fs, name)
400
+ class DcrWidgetsProxy:
401
+ def __init__(self):
402
+ self._values = {}
403
+ _dcr_overrides = globals().get('__dcr_widget_values', {})
404
+ self._overrides = dict(_dcr_overrides) if isinstance(_dcr_overrides, dict) else {}
405
+ def _register(self, name, defaultValue=''):
406
+ self._values.setdefault(name, defaultValue)
407
+ def text(self, name, defaultValue='', label=None):
408
+ self._register(name, defaultValue)
409
+ def dropdown(self, name, defaultValue='', choices=None, label=None):
410
+ self._register(name, defaultValue)
411
+ def combobox(self, name, defaultValue='', choices=None, label=None):
412
+ self._register(name, defaultValue)
413
+ def multiselect(self, name, defaultValue='', choices=None, label=None):
414
+ self._register(name, defaultValue)
415
+ def get(self, name):
416
+ if name in self._overrides and self._overrides[name] not in (None, ''):
417
+ return self._overrides[name]
418
+ return self._values.get(name, '')
419
+ def getArgument(self, name, defaultValue=''):
420
+ value = self.get(name)
421
+ return value if value != '' else defaultValue
422
+ def removeAll(self):
423
+ self._values.clear()
424
+ def dcr_workspace_host():
425
+ client = globals().get('__dcr_workspace_client')
426
+ if client is None:
427
+ try:
428
+ from databricks.sdk import WorkspaceClient
429
+ client = WorkspaceClient()
430
+ globals()['__dcr_workspace_client'] = client
431
+ except Exception:
432
+ client = None
433
+ if client is not None:
434
+ try:
435
+ host = client.config.host
436
+ if host:
437
+ return host
438
+ except Exception:
439
+ pass
440
+ return os.environ.get('DATABRICKS_HOST', '')
441
+ class DcrScalaOption:
442
+ def __init__(self, value):
443
+ self._value = value
444
+ def get(self):
445
+ return self._value
446
+ def getOrElse(self, default):
447
+ return self._value if self._value not in (None, '') else default
448
+ def isDefined(self):
449
+ return self._value not in (None, '')
450
+ def isEmpty(self):
451
+ return self._value in (None, '')
452
+ def toString(self):
453
+ return str(self._value if self._value is not None else '')
454
+ class DcrTagsMap:
455
+ def __init__(self, data=None):
456
+ self._data = data or {}
457
+ def apply(self, key):
458
+ return self._data.get(key, '')
459
+ def get(self, key, default=None):
460
+ return DcrScalaOption(self._data.get(key))
461
+ def getOrElse(self, key, default):
462
+ return self._data.get(key, default)
463
+ class DcrNotebookContext:
464
+ def _bare_host(self):
465
+ return dcr_workspace_host().replace('https://', '').replace('http://', '').rstrip('/')
466
+ def apiUrl(self):
467
+ return DcrScalaOption(dcr_workspace_host())
468
+ def workspaceUrl(self):
469
+ return DcrScalaOption(self._bare_host())
470
+ def browserHostName(self):
471
+ return DcrScalaOption(self._bare_host())
472
+ def notebookPath(self):
473
+ return DcrScalaOption(globals().get('__dcr_notebook_path', ''))
474
+ def tags(self):
475
+ return DcrTagsMap()
476
+ def __getattr__(self, name):
477
+ return lambda *args, **kwargs: DcrScalaOption(None)
478
+ class DcrNotebookContextHolder:
479
+ def getContext(self):
480
+ return DcrNotebookContext()
481
+ class DcrEntryPointDbutils:
482
+ def notebook(self):
483
+ return DcrNotebookContextHolder()
484
+ class DcrEntryPoint:
485
+ def getDbutils(self):
486
+ return DcrEntryPointDbutils()
487
+ class DcrNotebookProxy:
488
+ def __init__(self):
489
+ self.entry_point = DcrEntryPoint()
490
+ def exit(self, value=None):
491
+ raise DcrNotebookExit(value)
492
+ def run(self, path=None, timeout_seconds=None, arguments=None, *args, **kwargs):
493
+ print('[spark-cell-runner] Skipping dbutils.notebook.run(%r) in local execution' % (path,))
494
+ return ''
495
+ def getContext(self):
496
+ return DcrNotebookContext()
497
+ class DcrSecretsProxy:
498
+ def get(self, scope=None, key=None):
499
+ _dcr_secrets = globals().get('__dcr_secret_values', {})
500
+ scoped_key = f'{scope}/{key}' if scope and key else None
501
+ if scoped_key and scoped_key in _dcr_secrets:
502
+ return _dcr_secrets[scoped_key]
503
+ if key and key in _dcr_secrets:
504
+ return _dcr_secrets[key]
505
+ env_key = key or scoped_key or ''
506
+ env_key = env_key.replace('-', '_').replace('/', '_').upper()
507
+ if env_key and env_key in os.environ:
508
+ return os.environ[env_key]
509
+ return ''
510
+ class DcrLibraryProxy:
511
+ def __init__(self, wrapped):
512
+ self._wrapped = wrapped
513
+ def restartPython(self):
514
+ print('[spark-cell-runner] Skipping dbutils.library.restartPython() in local execution')
515
+ def __getattr__(self, name):
516
+ if self._wrapped is None:
517
+ raise AttributeError(name)
518
+ return getattr(self._wrapped.library, name)
519
+ class DcrDbutilsProxy:
520
+ def __init__(self, wrapped):
521
+ self._wrapped = wrapped
522
+ self.fs = DcrFsProxy(wrapped)
523
+ self.widgets = DcrWidgetsProxy()
524
+ self.notebook = DcrNotebookProxy()
525
+ self.secrets = DcrSecretsProxy()
526
+ self.library = DcrLibraryProxy(wrapped)
527
+ def __getattr__(self, name):
528
+ if self._wrapped is None:
529
+ raise AttributeError(name)
530
+ return getattr(self._wrapped, name)
531
+ try:
532
+ from databricks.sdk.runtime import dbutils as runtime_dbutils
533
+ except Exception:
534
+ runtime_dbutils = None
535
+ dbutils = globals().get('dbutils') or DcrDbutilsProxy(runtime_dbutils)
536
+ __SCR_CONNECTION_BLOCK__