better-dsh 0.3.0 → 0.3.1-a

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 (76) hide show
  1. package/README.md +49 -177
  2. package/cordis.patch.yml +5 -36
  3. package/docs/20_specs/kernel-provisioning/spec.md +2 -0
  4. package/docs/adr/0015-independent-bundles-agent-remote.md +40 -0
  5. package/docs/remote-tools.md +56 -0
  6. package/docs/specs/kernel-provisioning/spec.md +12 -40
  7. package/docs/specs/omp-python-repl-port/runtime-guide.md +35 -0
  8. package/docs/specs/omp-python-repl-port/spec.md +68 -0
  9. package/docs/specs/remote-tool-enhancement/spec.md +203 -0
  10. package/dsh-docs/baseline.md +13 -0
  11. package/dsh-docs/subsystems/invariants.md +3 -0
  12. package/dsh-docs/subsystems/invariants.zh.md +3 -0
  13. package/eval-description.md +7 -3
  14. package/lib/LaunchOptions-0Mr6meJc.js +4 -0
  15. package/lib/{LaunchOptions-kGXcZOe0.js → LaunchOptions-iE9M-STS.js} +1 -1
  16. package/lib/{bidi-BalpKaJc.js → bidi-CaQeBZHY.js} +1 -1
  17. package/lib/client/index.js +30 -6
  18. package/lib/failover/index.js +1 -1
  19. package/lib/fs-aware/sandbox-plugin.js +3 -3
  20. package/lib/{index-browser-CysrjMyM.js → index-browser-CJzxT9Vi.js} +4 -4
  21. package/lib/index.d.ts +16 -50
  22. package/lib/index.js +482 -1720
  23. package/lib/kernel-env-x_WkG6Fr.js +76 -0
  24. package/lib/kernel-env.d.ts +5 -69
  25. package/lib/kernel-env.js +2 -2
  26. package/lib/{lsp-server-registry-BXvUTBY7.js → lsp-server-registry-BcdkHROD.js} +1 -1
  27. package/lib/{lsp-server-registry-CH9WNFFt.js → lsp-server-registry-D4VLs1Sm.js} +1 -1
  28. package/lib/{main-BQeFrBM1.js → main-taSMz1KX.js} +1 -1
  29. package/lib/{main-CupOhMp5.js → main-uqGqYYnA.js} +7 -5
  30. package/lib/mobile/plugin.d.ts +1 -1
  31. package/lib/omp-python/DILL-LICENSE +35 -0
  32. package/lib/omp-python/OMP-LICENSE +23 -0
  33. package/lib/omp-python/better_snapshot.py +391 -0
  34. package/lib/omp-python/better_support.py +425 -0
  35. package/lib/omp-python/dill-provenance.json +55 -0
  36. package/lib/omp-python/provenance.json +13 -0
  37. package/lib/omp-python/runner.py +2499 -0
  38. package/lib/omp-python/vendor/dill/__diff.py +234 -0
  39. package/lib/omp-python/vendor/dill/__info__.py +291 -0
  40. package/lib/omp-python/vendor/dill/__init__.py +119 -0
  41. package/lib/omp-python/vendor/dill/_dill.py +2265 -0
  42. package/lib/omp-python/vendor/dill/_objects.py +545 -0
  43. package/lib/omp-python/vendor/dill/_shims.py +193 -0
  44. package/lib/omp-python/vendor/dill/detect.py +287 -0
  45. package/lib/omp-python/vendor/dill/logger.py +285 -0
  46. package/lib/omp-python/vendor/dill/objtypes.py +24 -0
  47. package/lib/omp-python/vendor/dill/pointers.py +122 -0
  48. package/lib/omp-python/vendor/dill/session.py +612 -0
  49. package/lib/omp-python/vendor/dill/settings.py +25 -0
  50. package/lib/omp-python/vendor/dill/source.py +1025 -0
  51. package/lib/omp-python/vendor/dill/temp.py +252 -0
  52. package/lib/{puppeteer-core-CSk2PtSm.js → puppeteer-core-C-4NyOpY.js} +8 -8
  53. package/lib/remote/plugin.d.ts +459 -5
  54. package/lib/remote/plugin.js +2389 -210
  55. package/lib/url-schemes/index.d.ts +11 -11
  56. package/lib/url-schemes/index.js +11 -11
  57. package/lib/web-password.d.ts +8 -8
  58. package/lib/web-password.js +5 -1
  59. package/lib/{web-trust-Dej_RI2B.d.ts → web-trust-C_Y6o8Z2.d.ts} +11 -11
  60. package/lib/web-trust.d.ts +1 -2
  61. package/lib/welcome-notice.d.ts +5 -7
  62. package/lib/welcome-notice.js +9 -48
  63. package/lib/{wrap-T4I0nfPM.js → wrap-0VA0uFx8.js} +1 -1
  64. package/package.json +7 -24
  65. package/scripts/kernel-check.mjs +5 -0
  66. package/lib/LaunchOptions-B874eBu2.js +0 -4
  67. package/lib/bundle-delivery.d.ts +0 -20
  68. package/lib/bundle-delivery.js +0 -209
  69. package/lib/hmr.d.ts +0 -32
  70. package/lib/hmr.js +0 -49
  71. package/lib/kernel-bridge.py +0 -172
  72. package/lib/kernel-env-D8UOWeji.js +0 -195
  73. package/lib/webserver.d.ts +0 -10
  74. package/lib/webserver.js +0 -19
  75. package/scripts/kernel-provision.mjs +0 -35
  76. package/scripts/register-bundle.mjs +0 -80
@@ -0,0 +1,285 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ # Author: Leonardo Gama (@leogama)
5
+ # Copyright (c) 2022-2026 The Uncertainty Quantification Foundation.
6
+ # License: 3-clause BSD. The full license text is available at:
7
+ # - https://github.com/uqfoundation/dill/blob/master/LICENSE
8
+ """
9
+ Logging utilities for dill.
10
+
11
+ The 'logger' object is dill's top-level logger.
12
+
13
+ The 'adapter' object wraps the logger and implements a 'trace()' method that
14
+ generates a detailed tree-style trace for the pickling call at log level INFO.
15
+
16
+ The 'trace()' function sets and resets dill's logger log level, enabling and
17
+ disabling the pickling trace.
18
+
19
+ The trace shows a tree structure depicting the depth of each object serialized
20
+ *with dill save functions*, but not the ones that use save functions from
21
+ 'pickle._Pickler.dispatch'. If the information is available, it also displays
22
+ the size in bytes that the object contributed to the pickle stream (including
23
+ its child objects). Sample trace output:
24
+
25
+ >>> import dill, dill.tests
26
+ >>> dill.detect.trace(True)
27
+ >>> dill.dump_session(main=dill.tests)
28
+ ┬ M1: <module 'dill.tests' from '.../dill/tests/__init__.py'>
29
+ ├┬ F2: <function _import_module at 0x7f0d2dce1b80>
30
+ │└ # F2 [32 B]
31
+ ├┬ D2: <dict object at 0x7f0d2e98a540>
32
+ │├┬ T4: <class '_frozen_importlib.ModuleSpec'>
33
+ ││└ # T4 [35 B]
34
+ │├┬ D2: <dict object at 0x7f0d2ef0e8c0>
35
+ ││├┬ T4: <class '_frozen_importlib_external.SourceFileLoader'>
36
+ │││└ # T4 [50 B]
37
+ ││├┬ D2: <dict object at 0x7f0d2e988a40>
38
+ │││└ # D2 [84 B]
39
+ ││└ # D2 [413 B]
40
+ │└ # D2 [763 B]
41
+ └ # M1 [813 B]
42
+ """
43
+
44
+ __all__ = ['adapter', 'logger', 'trace']
45
+
46
+ import codecs
47
+ import contextlib
48
+ import locale
49
+ import logging
50
+ import math
51
+ import os
52
+ from functools import partial
53
+ from typing import TextIO, Union
54
+
55
+ import dill
56
+
57
+ # Tree drawing characters: Unicode to ASCII map.
58
+ ASCII_MAP = str.maketrans({"│": "|", "├": "|", "┬": "+", "└": "`"})
59
+
60
+ ## Notes about the design choices ##
61
+
62
+ # Here is some domumentation of the Standard Library's logging internals that
63
+ # can't be found completely in the official documentation. dill's logger is
64
+ # obtained by calling logging.getLogger('dill') and therefore is an instance of
65
+ # logging.getLoggerClass() at the call time. As this is controlled by the user,
66
+ # in order to add some functionality to it it's necessary to use a LoggerAdapter
67
+ # to wrap it, overriding some of the adapter's methods and creating new ones.
68
+ #
69
+ # Basic calling sequence
70
+ # ======================
71
+ #
72
+ # Python's logging functionality can be conceptually divided into five steps:
73
+ # 0. Check logging level -> abort if call level is greater than logger level
74
+ # 1. Gather information -> construct a LogRecord from passed arguments and context
75
+ # 2. Filter (optional) -> discard message if the record matches a filter
76
+ # 3. Format -> format message with args, then format output string with message plus record
77
+ # 4. Handle -> write the formatted string to output as defined in the handler
78
+ #
79
+ # dill.logging.logger.log -> # or logger.info, etc.
80
+ # Logger.log -> \
81
+ # Logger._log -> }- accept 'extra' parameter for custom record entries
82
+ # Logger.makeRecord -> /
83
+ # LogRecord.__init__
84
+ # Logger.handle ->
85
+ # Logger.callHandlers ->
86
+ # Handler.handle ->
87
+ # Filterer.filter ->
88
+ # Filter.filter
89
+ # StreamHandler.emit ->
90
+ # Handler.format ->
91
+ # Formatter.format ->
92
+ # LogRecord.getMessage # does: record.message = msg % args
93
+ # Formatter.formatMessage ->
94
+ # PercentStyle.format # does: self._fmt % vars(record)
95
+ #
96
+ # NOTE: All methods from the second line on are from logging.__init__.py
97
+
98
+ class TraceAdapter(logging.LoggerAdapter):
99
+ """
100
+ Tracks object tree depth and calculates pickled object size.
101
+
102
+ A single instance of this wraps the module's logger, as the logging API
103
+ doesn't allow setting it directly with a custom Logger subclass. The added
104
+ 'trace()' method receives a pickle instance as the first argument and
105
+ creates extra values to be added in the LogRecord from it, then calls
106
+ 'info()'.
107
+
108
+ Usage of logger with 'trace()' method:
109
+
110
+ >>> from dill.logger import adapter as logger #NOTE: not dill.logger.logger
111
+ >>> ...
112
+ >>> def save_atype(pickler, obj):
113
+ >>> logger.trace(pickler, "Message with %s and %r etc. placeholders", 'text', obj)
114
+ >>> ...
115
+ """
116
+ def __init__(self, logger):
117
+ self.logger = logger
118
+ def addHandler(self, handler):
119
+ formatter = TraceFormatter("%(prefix)s%(message)s%(suffix)s", handler=handler)
120
+ handler.setFormatter(formatter)
121
+ self.logger.addHandler(handler)
122
+ def removeHandler(self, handler):
123
+ self.logger.removeHandler(handler)
124
+ def process(self, msg, kwargs):
125
+ # A no-op override, as we don't have self.extra.
126
+ return msg, kwargs
127
+ def trace_setup(self, pickler):
128
+ # Called by Pickler.dump().
129
+ if not dill._dill.is_dill(pickler, child=False):
130
+ return
131
+ if self.isEnabledFor(logging.INFO):
132
+ pickler._trace_depth = 1
133
+ pickler._size_stack = []
134
+ else:
135
+ pickler._trace_depth = None
136
+ def trace(self, pickler, msg, *args, **kwargs):
137
+ if not hasattr(pickler, '_trace_depth'):
138
+ logger.info(msg, *args, **kwargs)
139
+ return
140
+ if pickler._trace_depth is None:
141
+ return
142
+ extra = kwargs.get('extra', {})
143
+ pushed_obj = msg.startswith('#')
144
+ size = None
145
+ try:
146
+ # Streams are not required to be tellable.
147
+ size = pickler._file.tell()
148
+ frame = pickler.framer.current_frame
149
+ try:
150
+ size += frame.tell()
151
+ except AttributeError:
152
+ # PyPy may use a BytesBuilder as frame
153
+ size += len(frame)
154
+ except (AttributeError, TypeError):
155
+ pass
156
+ if size is not None:
157
+ if not pushed_obj:
158
+ pickler._size_stack.append(size)
159
+ else:
160
+ size -= pickler._size_stack.pop()
161
+ extra['size'] = size
162
+ if pushed_obj:
163
+ pickler._trace_depth -= 1
164
+ extra['depth'] = pickler._trace_depth
165
+ kwargs['extra'] = extra
166
+ self.info(msg, *args, **kwargs)
167
+ if not pushed_obj:
168
+ pickler._trace_depth += 1
169
+
170
+ class TraceFormatter(logging.Formatter):
171
+ """
172
+ Generates message prefix and suffix from record.
173
+
174
+ This Formatter adds prefix and suffix strings to the log message in trace
175
+ mode (an also provides empty string defaults for normal logs).
176
+ """
177
+ def __init__(self, *args, handler=None, **kwargs):
178
+ super().__init__(*args, **kwargs)
179
+ try:
180
+ encoding = handler.stream.encoding
181
+ if encoding is None:
182
+ raise AttributeError
183
+ except AttributeError:
184
+ encoding = locale.getpreferredencoding()
185
+ try:
186
+ encoding = codecs.lookup(encoding).name
187
+ except LookupError:
188
+ self.is_utf8 = False
189
+ else:
190
+ self.is_utf8 = (encoding == codecs.lookup('utf-8').name)
191
+ def format(self, record):
192
+ fields = {'prefix': "", 'suffix': ""}
193
+ if getattr(record, 'depth', 0) > 0:
194
+ if record.msg.startswith("#"):
195
+ prefix = (record.depth - 1)*"│" + "└"
196
+ elif record.depth == 1:
197
+ prefix = "┬"
198
+ else:
199
+ prefix = (record.depth - 2)*"│" + "├┬"
200
+ if not self.is_utf8:
201
+ prefix = prefix.translate(ASCII_MAP) + "-"
202
+ fields['prefix'] = prefix + " "
203
+ if hasattr(record, 'size') and record.size is not None and record.size >= 1:
204
+ # Show object size in human-readable form.
205
+ power = int(math.log(record.size, 2)) // 10
206
+ size = record.size >> power*10
207
+ fields['suffix'] = " [%d %sB]" % (size, "KMGTP"[power] + "i" if power else "")
208
+ vars(record).update(fields)
209
+ return super().format(record)
210
+
211
+ logger = logging.getLogger('dill')
212
+ logger.propagate = False
213
+ adapter = TraceAdapter(logger)
214
+ stderr_handler = logging._StderrHandler()
215
+ adapter.addHandler(stderr_handler)
216
+
217
+ def trace(arg: Union[bool, TextIO, str, os.PathLike] = None, *, mode: str = 'a') -> None:
218
+ """print a trace through the stack when pickling; useful for debugging
219
+
220
+ With a single boolean argument, enable or disable the tracing.
221
+
222
+ Example usage:
223
+
224
+ >>> import dill
225
+ >>> dill.detect.trace(True)
226
+ >>> dill.dump_session()
227
+
228
+ Alternatively, ``trace()`` can be used as a context manager. With no
229
+ arguments, it just takes care of restoring the tracing state on exit.
230
+ Either a file handle, or a file name and (optionally) a file mode may be
231
+ specitfied to redirect the tracing output in the ``with`` block context. A
232
+ log function is yielded by the manager so the user can write extra
233
+ information to the file.
234
+
235
+ Example usage:
236
+
237
+ >>> from dill import detect
238
+ >>> D = {'a': 42, 'b': {'x': None}}
239
+ >>> with detect.trace():
240
+ >>> dumps(D)
241
+ ┬ D2: <dict object at 0x7f2721804800>
242
+ ├┬ D2: <dict object at 0x7f27217f5c40>
243
+ │└ # D2 [8 B]
244
+ └ # D2 [22 B]
245
+ >>> squared = lambda x: x**2
246
+ >>> with detect.trace('output.txt', mode='w') as log:
247
+ >>> log("> D = %r", D)
248
+ >>> dumps(D)
249
+ >>> log("> squared = %r", squared)
250
+ >>> dumps(squared)
251
+
252
+ Arguments:
253
+ arg: a boolean value, or an optional file-like or path-like object for the context manager
254
+ mode: mode string for ``open()`` if a file name is passed as the first argument
255
+ """
256
+ if repr(arg) not in ('False', 'True'):
257
+ return TraceManager(file=arg, mode=mode)
258
+ logger.setLevel(logging.INFO if arg else logging.WARNING)
259
+
260
+ class TraceManager(contextlib.AbstractContextManager):
261
+ """context manager version of trace(); can redirect the trace to a file"""
262
+ def __init__(self, file, mode):
263
+ self.file = file
264
+ self.mode = mode
265
+ self.redirect = file is not None
266
+ self.file_is_stream = hasattr(file, 'write')
267
+ def __enter__(self):
268
+ if self.redirect:
269
+ stderr_handler.flush()
270
+ if self.file_is_stream:
271
+ self.handler = logging.StreamHandler(self.file)
272
+ else:
273
+ self.handler = logging.FileHandler(self.file, self.mode)
274
+ adapter.removeHandler(stderr_handler)
275
+ adapter.addHandler(self.handler)
276
+ self.old_level = adapter.getEffectiveLevel()
277
+ adapter.setLevel(logging.INFO)
278
+ return adapter.info
279
+ def __exit__(self, *exc_info):
280
+ adapter.setLevel(self.old_level)
281
+ if self.redirect:
282
+ adapter.removeHandler(self.handler)
283
+ adapter.addHandler(stderr_handler)
284
+ if not self.file_is_stream:
285
+ self.handler.close()
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env python
2
+ #
3
+ # Author: Mike McKerns (mmckerns @caltech and @uqfoundation)
4
+ # Copyright (c) 2008-2016 California Institute of Technology.
5
+ # Copyright (c) 2016-2026 The Uncertainty Quantification Foundation.
6
+ # License: 3-clause BSD. The full license text is available at:
7
+ # - https://github.com/uqfoundation/dill/blob/master/LICENSE
8
+ """
9
+ all Python Standard Library object types (currently: CH 1-15 @ 2.7)
10
+ and some other common object types (i.e. numpy.ndarray)
11
+
12
+ to load more objects and types, use dill.load_types()
13
+ """
14
+
15
+ # non-local import of dill.objects
16
+ from dill import objects
17
+ for _type in objects.keys():
18
+ exec("%s = type(objects['%s'])" % (_type,_type))
19
+
20
+ del objects
21
+ try:
22
+ del _type
23
+ except NameError:
24
+ pass
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env python
2
+ #
3
+ # Author: Mike McKerns (mmckerns @caltech and @uqfoundation)
4
+ # Copyright (c) 2008-2016 California Institute of Technology.
5
+ # Copyright (c) 2016-2026 The Uncertainty Quantification Foundation.
6
+ # License: 3-clause BSD. The full license text is available at:
7
+ # - https://github.com/uqfoundation/dill/blob/master/LICENSE
8
+
9
+ __all__ = ['parent', 'reference', 'at', 'parents', 'children']
10
+
11
+ import gc
12
+ import sys
13
+
14
+ from ._dill import _proxy_helper as reference
15
+ from ._dill import _locate_object as at
16
+
17
+ def parent(obj, objtype, ignore=()):
18
+ """
19
+ >>> listiter = iter([4,5,6,7])
20
+ >>> obj = parent(listiter, list)
21
+ >>> obj == [4,5,6,7] # actually 'is', but don't have handle any longer
22
+ True
23
+
24
+ NOTE: objtype can be a single type (e.g. int or list) or a tuple of types.
25
+
26
+ WARNING: if obj is a sequence (e.g. list), may produce unexpected results.
27
+ Parent finds *one* parent (e.g. the last member of the sequence).
28
+ """
29
+ depth = 1 #XXX: always looking for the parent (only, right?)
30
+ chain = parents(obj, objtype, depth, ignore)
31
+ parent = chain.pop()
32
+ if parent is obj:
33
+ return None
34
+ return parent
35
+
36
+
37
+ def parents(obj, objtype, depth=1, ignore=()): #XXX: objtype=object ?
38
+ """Find the chain of referents for obj. Chain will end with obj.
39
+
40
+ objtype: an object type or tuple of types to search for
41
+ depth: search depth (e.g. depth=2 is 'grandparents')
42
+ ignore: an object or tuple of objects to ignore in the search
43
+ """
44
+ edge_func = gc.get_referents # looking for refs, not back_refs
45
+ predicate = lambda x: isinstance(x, objtype) # looking for parent type
46
+ #if objtype is None: predicate = lambda x: True #XXX: in obj.mro() ?
47
+ ignore = (ignore,) if not hasattr(ignore, '__len__') else ignore
48
+ ignore = (id(obj) for obj in ignore)
49
+ chain = find_chain(obj, predicate, edge_func, depth)[::-1]
50
+ #XXX: should pop off obj... ?
51
+ return chain
52
+
53
+
54
+ def children(obj, objtype, depth=1, ignore=()): #XXX: objtype=object ?
55
+ """Find the chain of referrers for obj. Chain will start with obj.
56
+
57
+ objtype: an object type or tuple of types to search for
58
+ depth: search depth (e.g. depth=2 is 'grandchildren')
59
+ ignore: an object or tuple of objects to ignore in the search
60
+
61
+ NOTE: a common thing to ignore is all globals, 'ignore=(globals(),)'
62
+
63
+ NOTE: repeated calls may yield different results, as python stores
64
+ the last value in the special variable '_'; thus, it is often good
65
+ to execute something to replace '_' (e.g. >>> 1+1).
66
+ """
67
+ edge_func = gc.get_referrers # looking for back_refs, not refs
68
+ predicate = lambda x: isinstance(x, objtype) # looking for child type
69
+ #if objtype is None: predicate = lambda x: True #XXX: in obj.mro() ?
70
+ ignore = (ignore,) if not hasattr(ignore, '__len__') else ignore
71
+ ignore = (id(obj) for obj in ignore)
72
+ chain = find_chain(obj, predicate, edge_func, depth, ignore)
73
+ #XXX: should pop off obj... ?
74
+ return chain
75
+
76
+
77
+ # more generic helper function (cut-n-paste from objgraph)
78
+ # Source at http://mg.pov.lt/objgraph/
79
+ # Copyright (c) 2008-2010 Marius Gedminas <marius@pov.lt>
80
+ # Copyright (c) 2010 Stefano Rivera <stefano@rivera.za.net>
81
+ # Released under the MIT licence (see objgraph/objgrah.py)
82
+
83
+ def find_chain(obj, predicate, edge_func, max_depth=20, extra_ignore=()):
84
+ queue = [obj]
85
+ depth = {id(obj): 0}
86
+ parent = {id(obj): None}
87
+ ignore = set(extra_ignore)
88
+ ignore.add(id(extra_ignore))
89
+ ignore.add(id(queue))
90
+ ignore.add(id(depth))
91
+ ignore.add(id(parent))
92
+ ignore.add(id(ignore))
93
+ ignore.add(id(sys._getframe())) # this function
94
+ ignore.add(id(sys._getframe(1))) # find_chain/find_backref_chain, likely
95
+ gc.collect()
96
+ while queue:
97
+ target = queue.pop(0)
98
+ if predicate(target):
99
+ chain = [target]
100
+ while parent[id(target)] is not None:
101
+ target = parent[id(target)]
102
+ chain.append(target)
103
+ return chain
104
+ tdepth = depth[id(target)]
105
+ if tdepth < max_depth:
106
+ referrers = edge_func(target)
107
+ ignore.add(id(referrers))
108
+ for source in referrers:
109
+ if id(source) in ignore:
110
+ continue
111
+ if id(source) not in depth:
112
+ depth[id(source)] = tdepth + 1
113
+ parent[id(source)] = target
114
+ queue.append(source)
115
+ return [obj] # not found
116
+
117
+
118
+ # backward compatibility
119
+ refobject = at
120
+
121
+
122
+ # EOF