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.
- package/README.md +49 -177
- package/cordis.patch.yml +5 -36
- package/docs/20_specs/kernel-provisioning/spec.md +2 -0
- package/docs/adr/0015-independent-bundles-agent-remote.md +40 -0
- package/docs/remote-tools.md +56 -0
- package/docs/specs/kernel-provisioning/spec.md +12 -40
- package/docs/specs/omp-python-repl-port/runtime-guide.md +35 -0
- package/docs/specs/omp-python-repl-port/spec.md +68 -0
- package/docs/specs/remote-tool-enhancement/spec.md +203 -0
- package/dsh-docs/baseline.md +13 -0
- package/dsh-docs/subsystems/invariants.md +3 -0
- package/dsh-docs/subsystems/invariants.zh.md +3 -0
- package/eval-description.md +7 -3
- package/lib/LaunchOptions-0Mr6meJc.js +4 -0
- package/lib/{LaunchOptions-kGXcZOe0.js → LaunchOptions-iE9M-STS.js} +1 -1
- package/lib/{bidi-BalpKaJc.js → bidi-CaQeBZHY.js} +1 -1
- package/lib/client/index.js +30 -6
- package/lib/failover/index.js +1 -1
- package/lib/fs-aware/sandbox-plugin.js +3 -3
- package/lib/{index-browser-CysrjMyM.js → index-browser-CJzxT9Vi.js} +4 -4
- package/lib/index.d.ts +16 -50
- package/lib/index.js +482 -1720
- package/lib/kernel-env-x_WkG6Fr.js +76 -0
- package/lib/kernel-env.d.ts +5 -69
- package/lib/kernel-env.js +2 -2
- package/lib/{lsp-server-registry-BXvUTBY7.js → lsp-server-registry-BcdkHROD.js} +1 -1
- package/lib/{lsp-server-registry-CH9WNFFt.js → lsp-server-registry-D4VLs1Sm.js} +1 -1
- package/lib/{main-BQeFrBM1.js → main-taSMz1KX.js} +1 -1
- package/lib/{main-CupOhMp5.js → main-uqGqYYnA.js} +7 -5
- package/lib/mobile/plugin.d.ts +1 -1
- package/lib/omp-python/DILL-LICENSE +35 -0
- package/lib/omp-python/OMP-LICENSE +23 -0
- package/lib/omp-python/better_snapshot.py +391 -0
- package/lib/omp-python/better_support.py +425 -0
- package/lib/omp-python/dill-provenance.json +55 -0
- package/lib/omp-python/provenance.json +13 -0
- package/lib/omp-python/runner.py +2499 -0
- package/lib/omp-python/vendor/dill/__diff.py +234 -0
- package/lib/omp-python/vendor/dill/__info__.py +291 -0
- package/lib/omp-python/vendor/dill/__init__.py +119 -0
- package/lib/omp-python/vendor/dill/_dill.py +2265 -0
- package/lib/omp-python/vendor/dill/_objects.py +545 -0
- package/lib/omp-python/vendor/dill/_shims.py +193 -0
- package/lib/omp-python/vendor/dill/detect.py +287 -0
- package/lib/omp-python/vendor/dill/logger.py +285 -0
- package/lib/omp-python/vendor/dill/objtypes.py +24 -0
- package/lib/omp-python/vendor/dill/pointers.py +122 -0
- package/lib/omp-python/vendor/dill/session.py +612 -0
- package/lib/omp-python/vendor/dill/settings.py +25 -0
- package/lib/omp-python/vendor/dill/source.py +1025 -0
- package/lib/omp-python/vendor/dill/temp.py +252 -0
- package/lib/{puppeteer-core-CSk2PtSm.js → puppeteer-core-C-4NyOpY.js} +8 -8
- package/lib/remote/plugin.d.ts +459 -5
- package/lib/remote/plugin.js +2389 -210
- package/lib/url-schemes/index.d.ts +11 -11
- package/lib/url-schemes/index.js +11 -11
- package/lib/web-password.d.ts +8 -8
- package/lib/web-password.js +5 -1
- package/lib/{web-trust-Dej_RI2B.d.ts → web-trust-C_Y6o8Z2.d.ts} +11 -11
- package/lib/web-trust.d.ts +1 -2
- package/lib/welcome-notice.d.ts +5 -7
- package/lib/welcome-notice.js +9 -48
- package/lib/{wrap-T4I0nfPM.js → wrap-0VA0uFx8.js} +1 -1
- package/package.json +7 -24
- package/scripts/kernel-check.mjs +5 -0
- package/lib/LaunchOptions-B874eBu2.js +0 -4
- package/lib/bundle-delivery.d.ts +0 -20
- package/lib/bundle-delivery.js +0 -209
- package/lib/hmr.d.ts +0 -32
- package/lib/hmr.js +0 -49
- package/lib/kernel-bridge.py +0 -172
- package/lib/kernel-env-D8UOWeji.js +0 -195
- package/lib/webserver.d.ts +0 -10
- package/lib/webserver.js +0 -19
- package/scripts/kernel-provision.mjs +0 -35
- package/scripts/register-bundle.mjs +0 -80
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
#
|
|
3
|
+
# Author: Mike McKerns (mmckerns @caltech and @uqfoundation)
|
|
4
|
+
# Author: Anirudh Vegesana (avegesan@cs.stanford.edu)
|
|
5
|
+
# Copyright (c) 2021-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
|
+
Provides shims for compatibility between versions of dill and Python.
|
|
10
|
+
|
|
11
|
+
Compatibility shims should be provided in this file. Here are two simple example
|
|
12
|
+
use cases.
|
|
13
|
+
|
|
14
|
+
Deprecation of constructor function:
|
|
15
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
16
|
+
Assume that we were transitioning _import_module in _dill.py to
|
|
17
|
+
the builtin function importlib.import_module when present.
|
|
18
|
+
|
|
19
|
+
@move_to(_dill)
|
|
20
|
+
def _import_module(import_name):
|
|
21
|
+
... # code already in _dill.py
|
|
22
|
+
|
|
23
|
+
_import_module = Getattr(importlib, 'import_module', Getattr(_dill, '_import_module', None))
|
|
24
|
+
|
|
25
|
+
The code will attempt to find import_module in the importlib module. If not
|
|
26
|
+
present, it will use the _import_module function in _dill.
|
|
27
|
+
|
|
28
|
+
Emulate new Python behavior in older Python versions:
|
|
29
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
30
|
+
CellType.cell_contents behaves differently in Python 3.6 and 3.7. It is
|
|
31
|
+
read-only in Python 3.6 and writable and deletable in 3.7.
|
|
32
|
+
|
|
33
|
+
if _dill.OLD37 and _dill.HAS_CTYPES and ...:
|
|
34
|
+
@move_to(_dill)
|
|
35
|
+
def _setattr(object, name, value):
|
|
36
|
+
if type(object) is _dill.CellType and name == 'cell_contents':
|
|
37
|
+
_PyCell_Set.argtypes = (ctypes.py_object, ctypes.py_object)
|
|
38
|
+
_PyCell_Set(object, value)
|
|
39
|
+
else:
|
|
40
|
+
setattr(object, name, value)
|
|
41
|
+
... # more cases below
|
|
42
|
+
|
|
43
|
+
_setattr = Getattr(_dill, '_setattr', setattr)
|
|
44
|
+
|
|
45
|
+
_dill._setattr will be used when present to emulate Python 3.7 functionality in
|
|
46
|
+
older versions of Python while defaulting to the standard setattr in 3.7+.
|
|
47
|
+
|
|
48
|
+
See this PR for the discussion that lead to this system:
|
|
49
|
+
https://github.com/uqfoundation/dill/pull/443
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
import inspect
|
|
53
|
+
import sys
|
|
54
|
+
|
|
55
|
+
_dill = sys.modules['dill._dill']
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class Reduce(object):
|
|
59
|
+
"""
|
|
60
|
+
Reduce objects are wrappers used for compatibility enforcement during
|
|
61
|
+
unpickle-time. They should only be used in calls to pickler.save and
|
|
62
|
+
other Reduce objects. They are only evaluated within unpickler.load.
|
|
63
|
+
|
|
64
|
+
Pickling a Reduce object makes the two implementations equivalent:
|
|
65
|
+
|
|
66
|
+
pickler.save(Reduce(*reduction))
|
|
67
|
+
|
|
68
|
+
pickler.save_reduce(*reduction, obj=reduction)
|
|
69
|
+
"""
|
|
70
|
+
__slots__ = ['reduction']
|
|
71
|
+
def __new__(cls, *reduction, **kwargs):
|
|
72
|
+
"""
|
|
73
|
+
Args:
|
|
74
|
+
*reduction: a tuple that matches the format given here:
|
|
75
|
+
https://docs.python.org/3/library/pickle.html#object.__reduce__
|
|
76
|
+
is_callable: a bool to indicate that the object created by
|
|
77
|
+
unpickling `reduction` is callable. If true, the current Reduce
|
|
78
|
+
is allowed to be used as the function in further save_reduce calls
|
|
79
|
+
or Reduce objects.
|
|
80
|
+
"""
|
|
81
|
+
is_callable = kwargs.get('is_callable', False) # Pleases Py2. Can be removed later
|
|
82
|
+
if is_callable:
|
|
83
|
+
self = object.__new__(_CallableReduce)
|
|
84
|
+
else:
|
|
85
|
+
self = object.__new__(Reduce)
|
|
86
|
+
self.reduction = reduction
|
|
87
|
+
return self
|
|
88
|
+
def __repr__(self):
|
|
89
|
+
return 'Reduce%s' % (self.reduction,)
|
|
90
|
+
def __copy__(self):
|
|
91
|
+
return self # pragma: no cover
|
|
92
|
+
def __deepcopy__(self, memo):
|
|
93
|
+
return self # pragma: no cover
|
|
94
|
+
def __reduce__(self):
|
|
95
|
+
return self.reduction
|
|
96
|
+
def __reduce_ex__(self, protocol):
|
|
97
|
+
return self.__reduce__()
|
|
98
|
+
|
|
99
|
+
class _CallableReduce(Reduce):
|
|
100
|
+
# A version of Reduce for functions. Used to trick pickler.save_reduce into
|
|
101
|
+
# thinking that Reduce objects of functions are themselves meaningful functions.
|
|
102
|
+
def __call__(self, *args, **kwargs):
|
|
103
|
+
reduction = self.__reduce__()
|
|
104
|
+
func = reduction[0]
|
|
105
|
+
f_args = reduction[1]
|
|
106
|
+
obj = func(*f_args)
|
|
107
|
+
return obj(*args, **kwargs)
|
|
108
|
+
|
|
109
|
+
__NO_DEFAULT = _dill.Sentinel('Getattr.NO_DEFAULT')
|
|
110
|
+
|
|
111
|
+
def Getattr(object, name, default=__NO_DEFAULT):
|
|
112
|
+
"""
|
|
113
|
+
A Reduce object that represents the getattr operation. When unpickled, the
|
|
114
|
+
Getattr will access an attribute 'name' of 'object' and return the value
|
|
115
|
+
stored there. If the attribute doesn't exist, the default value will be
|
|
116
|
+
returned if present.
|
|
117
|
+
|
|
118
|
+
The following statements are equivalent:
|
|
119
|
+
|
|
120
|
+
Getattr(collections, 'OrderedDict')
|
|
121
|
+
Getattr(collections, 'spam', None)
|
|
122
|
+
Getattr(*args)
|
|
123
|
+
|
|
124
|
+
Reduce(getattr, (collections, 'OrderedDict'))
|
|
125
|
+
Reduce(getattr, (collections, 'spam', None))
|
|
126
|
+
Reduce(getattr, args)
|
|
127
|
+
|
|
128
|
+
During unpickling, the first two will result in collections.OrderedDict and
|
|
129
|
+
None respectively because the first attribute exists and the second one does
|
|
130
|
+
not, forcing it to use the default value given in the third argument.
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
if default is Getattr.NO_DEFAULT:
|
|
134
|
+
reduction = (getattr, (object, name))
|
|
135
|
+
else:
|
|
136
|
+
reduction = (getattr, (object, name, default))
|
|
137
|
+
|
|
138
|
+
return Reduce(*reduction, is_callable=callable(default))
|
|
139
|
+
|
|
140
|
+
Getattr.NO_DEFAULT = __NO_DEFAULT
|
|
141
|
+
del __NO_DEFAULT
|
|
142
|
+
|
|
143
|
+
def move_to(module, name=None):
|
|
144
|
+
def decorator(func):
|
|
145
|
+
if name is None:
|
|
146
|
+
fname = func.__name__
|
|
147
|
+
else:
|
|
148
|
+
fname = name
|
|
149
|
+
module.__dict__[fname] = func
|
|
150
|
+
func.__module__ = module.__name__
|
|
151
|
+
return func
|
|
152
|
+
return decorator
|
|
153
|
+
|
|
154
|
+
def register_shim(name, default):
|
|
155
|
+
"""
|
|
156
|
+
A easier to understand and more compact way of "softly" defining a function.
|
|
157
|
+
These two pieces of code are equivalent:
|
|
158
|
+
|
|
159
|
+
if _dill.OLD3X:
|
|
160
|
+
def _create_class():
|
|
161
|
+
...
|
|
162
|
+
_create_class = register_shim('_create_class', types.new_class)
|
|
163
|
+
|
|
164
|
+
if _dill.OLD3X:
|
|
165
|
+
@move_to(_dill)
|
|
166
|
+
def _create_class():
|
|
167
|
+
...
|
|
168
|
+
_create_class = Getattr(_dill, '_create_class', types.new_class)
|
|
169
|
+
|
|
170
|
+
Intuitively, it creates a function or object in the versions of dill/python
|
|
171
|
+
that require special reimplementations, and use a core library or default
|
|
172
|
+
implementation if that function or object does not exist.
|
|
173
|
+
"""
|
|
174
|
+
func = globals().get(name)
|
|
175
|
+
if func is not None:
|
|
176
|
+
_dill.__dict__[name] = func
|
|
177
|
+
func.__module__ = _dill.__name__
|
|
178
|
+
|
|
179
|
+
if default is Getattr.NO_DEFAULT:
|
|
180
|
+
reduction = (getattr, (_dill, name))
|
|
181
|
+
else:
|
|
182
|
+
reduction = (getattr, (_dill, name, default))
|
|
183
|
+
|
|
184
|
+
return Reduce(*reduction, is_callable=callable(default))
|
|
185
|
+
|
|
186
|
+
######################
|
|
187
|
+
## Compatibility Shims are defined below
|
|
188
|
+
######################
|
|
189
|
+
|
|
190
|
+
_CELL_EMPTY = register_shim('_CELL_EMPTY', None)
|
|
191
|
+
|
|
192
|
+
_setattr = register_shim('_setattr', setattr)
|
|
193
|
+
_delattr = register_shim('_delattr', delattr)
|
|
@@ -0,0 +1,287 @@
|
|
|
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
|
+
Methods for detecting objects leading to pickling failures.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import dis
|
|
13
|
+
from inspect import ismethod, isfunction, istraceback, isframe, iscode
|
|
14
|
+
|
|
15
|
+
from .pointers import parent, reference, at, parents, children
|
|
16
|
+
from .logger import trace
|
|
17
|
+
|
|
18
|
+
__all__ = ['baditems','badobjects','badtypes','code','errors','freevars',
|
|
19
|
+
'getmodule','globalvars','nestedcode','nestedglobals','outermost',
|
|
20
|
+
'referredglobals','referrednested','trace','varnames']
|
|
21
|
+
|
|
22
|
+
def getmodule(object, _filename=None, force=False):
|
|
23
|
+
"""get the module of the object"""
|
|
24
|
+
from inspect import getmodule as getmod
|
|
25
|
+
module = getmod(object, _filename)
|
|
26
|
+
if module or not force: return module
|
|
27
|
+
import builtins
|
|
28
|
+
from .source import getname
|
|
29
|
+
name = getname(object, force=True)
|
|
30
|
+
return builtins if name in vars(builtins).keys() else None
|
|
31
|
+
|
|
32
|
+
def outermost(func): # is analogous to getsource(func,enclosing=True)
|
|
33
|
+
"""get outermost enclosing object (i.e. the outer function in a closure)
|
|
34
|
+
|
|
35
|
+
NOTE: this is the object-equivalent of getsource(func, enclosing=True)
|
|
36
|
+
"""
|
|
37
|
+
if ismethod(func):
|
|
38
|
+
_globals = func.__func__.__globals__ or {}
|
|
39
|
+
elif isfunction(func):
|
|
40
|
+
_globals = func.__globals__ or {}
|
|
41
|
+
else:
|
|
42
|
+
return #XXX: or raise? no matches
|
|
43
|
+
_globals = _globals.items()
|
|
44
|
+
# get the enclosing source
|
|
45
|
+
from .source import getsourcelines
|
|
46
|
+
try: lines,lnum = getsourcelines(func, enclosing=True)
|
|
47
|
+
except Exception: #TypeError, IOError
|
|
48
|
+
lines,lnum = [],None
|
|
49
|
+
code = ''.join(lines)
|
|
50
|
+
# get all possible names,objects that are named in the enclosing source
|
|
51
|
+
_locals = ((name,obj) for (name,obj) in _globals if name in code)
|
|
52
|
+
# now only save the objects that generate the enclosing block
|
|
53
|
+
for name,obj in _locals: #XXX: don't really need 'name'
|
|
54
|
+
try:
|
|
55
|
+
if getsourcelines(obj) == (lines,lnum): return obj
|
|
56
|
+
except Exception: #TypeError, IOError
|
|
57
|
+
pass
|
|
58
|
+
return #XXX: or raise? no matches
|
|
59
|
+
|
|
60
|
+
def nestedcode(func, recurse=True): #XXX: or return dict of {co_name: co} ?
|
|
61
|
+
"""get the code objects for any nested functions (e.g. in a closure)"""
|
|
62
|
+
func = code(func)
|
|
63
|
+
if not iscode(func): return [] #XXX: or raise? no matches
|
|
64
|
+
nested = set()
|
|
65
|
+
for co in func.co_consts:
|
|
66
|
+
if co is None: continue
|
|
67
|
+
co = code(co)
|
|
68
|
+
if co:
|
|
69
|
+
nested.add(co)
|
|
70
|
+
if recurse: nested |= set(nestedcode(co, recurse=True))
|
|
71
|
+
return list(nested)
|
|
72
|
+
|
|
73
|
+
def code(func):
|
|
74
|
+
"""get the code object for the given function or method
|
|
75
|
+
|
|
76
|
+
NOTE: use dill.source.getsource(CODEOBJ) to get the source code
|
|
77
|
+
"""
|
|
78
|
+
if ismethod(func): func = func.__func__
|
|
79
|
+
if isfunction(func): func = func.__code__
|
|
80
|
+
if istraceback(func): func = func.tb_frame
|
|
81
|
+
if isframe(func): func = func.f_code
|
|
82
|
+
if iscode(func): return func
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
#XXX: ugly: parse dis.dis for name after "<code object" in line and in globals?
|
|
86
|
+
def referrednested(func, recurse=True): #XXX: return dict of {__name__: obj} ?
|
|
87
|
+
"""get functions defined inside of func (e.g. inner functions in a closure)
|
|
88
|
+
|
|
89
|
+
NOTE: results may differ if the function has been executed or not.
|
|
90
|
+
If len(nestedcode(func)) > len(referrednested(func)), try calling func().
|
|
91
|
+
If possible, python builds code objects, but delays building functions
|
|
92
|
+
until func() is called.
|
|
93
|
+
"""
|
|
94
|
+
import gc
|
|
95
|
+
funcs = set()
|
|
96
|
+
# get the code objects, and try to track down by referrence
|
|
97
|
+
for co in nestedcode(func, recurse):
|
|
98
|
+
# look for function objects that refer to the code object
|
|
99
|
+
for obj in gc.get_referrers(co):
|
|
100
|
+
# get methods
|
|
101
|
+
_ = getattr(obj, '__func__', None) # ismethod
|
|
102
|
+
if getattr(_, '__code__', None) is co: funcs.add(obj)
|
|
103
|
+
# get functions
|
|
104
|
+
elif getattr(obj, '__code__', None) is co: funcs.add(obj)
|
|
105
|
+
# get frame objects
|
|
106
|
+
elif getattr(obj, 'f_code', None) is co: funcs.add(obj)
|
|
107
|
+
# get code objects
|
|
108
|
+
elif hasattr(obj, 'co_code') and obj is co: funcs.add(obj)
|
|
109
|
+
# frameobjs => func.__code__.co_varnames not in func.__code__.co_cellvars
|
|
110
|
+
# funcobjs => func.__code__.co_cellvars not in func.__code__.co_varnames
|
|
111
|
+
# frameobjs are not found, however funcobjs are...
|
|
112
|
+
# (see: test_mixins.quad ... and test_mixins.wtf)
|
|
113
|
+
# after execution, code objects get compiled, and then may be found by gc
|
|
114
|
+
return list(funcs)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def freevars(func):
|
|
118
|
+
"""get objects defined in enclosing code that are referred to by func
|
|
119
|
+
|
|
120
|
+
returns a dict of {name:object}"""
|
|
121
|
+
if ismethod(func): func = func.__func__
|
|
122
|
+
if isfunction(func):
|
|
123
|
+
closures = func.__closure__ or ()
|
|
124
|
+
func = func.__code__.co_freevars # get freevars
|
|
125
|
+
else:
|
|
126
|
+
return {}
|
|
127
|
+
|
|
128
|
+
def get_cell_contents():
|
|
129
|
+
for name, c in zip(func, closures):
|
|
130
|
+
try:
|
|
131
|
+
cell_contents = c.cell_contents
|
|
132
|
+
except ValueError: # cell is empty
|
|
133
|
+
continue
|
|
134
|
+
yield name, c.cell_contents
|
|
135
|
+
|
|
136
|
+
return dict(get_cell_contents())
|
|
137
|
+
|
|
138
|
+
# thanks to Davies Liu for recursion of globals
|
|
139
|
+
def nestedglobals(func, recurse=True):
|
|
140
|
+
"""get the names of any globals found within func"""
|
|
141
|
+
func = code(func)
|
|
142
|
+
if func is None: return list()
|
|
143
|
+
import sys
|
|
144
|
+
from .temp import capture
|
|
145
|
+
CAN_NULL = sys.hexversion >= 0x30b00a7 # NULL may be prepended >= 3.11a7
|
|
146
|
+
names = set()
|
|
147
|
+
with capture('stdout') as out:
|
|
148
|
+
try:
|
|
149
|
+
dis.dis(func) #XXX: dis.dis(None) disassembles last traceback
|
|
150
|
+
except IndexError:
|
|
151
|
+
pass #FIXME: HACK for IS_PYPY (3.11)
|
|
152
|
+
for line in out.getvalue().splitlines():
|
|
153
|
+
if '_GLOBAL' in line:
|
|
154
|
+
name = line.split('(')[-1].split(')')[0]
|
|
155
|
+
if CAN_NULL:
|
|
156
|
+
names.add(name.replace('NULL + ', '').replace(' + NULL', ''))
|
|
157
|
+
else:
|
|
158
|
+
names.add(name)
|
|
159
|
+
for co in getattr(func, 'co_consts', tuple()):
|
|
160
|
+
if co and recurse and iscode(co):
|
|
161
|
+
names.update(nestedglobals(co, recurse=True))
|
|
162
|
+
return list(names)
|
|
163
|
+
|
|
164
|
+
def referredglobals(func, recurse=True, builtin=False):
|
|
165
|
+
"""get the names of objects in the global scope referred to by func"""
|
|
166
|
+
return globalvars(func, recurse, builtin).keys()
|
|
167
|
+
|
|
168
|
+
def globalvars(func, recurse=True, builtin=False):
|
|
169
|
+
"""get objects defined in global scope that are referred to by func
|
|
170
|
+
|
|
171
|
+
return a dict of {name:object}"""
|
|
172
|
+
if ismethod(func): func = func.__func__
|
|
173
|
+
if isfunction(func):
|
|
174
|
+
globs = vars(getmodule(sum)).copy() if builtin else {}
|
|
175
|
+
# get references from within closure
|
|
176
|
+
orig_func, func = func, set()
|
|
177
|
+
for obj in orig_func.__closure__ or {}:
|
|
178
|
+
try:
|
|
179
|
+
cell_contents = obj.cell_contents
|
|
180
|
+
except ValueError: # cell is empty
|
|
181
|
+
pass
|
|
182
|
+
else:
|
|
183
|
+
_vars = globalvars(cell_contents, recurse, builtin) or {}
|
|
184
|
+
func.update(_vars) #XXX: (above) be wary of infinte recursion?
|
|
185
|
+
globs.update(_vars)
|
|
186
|
+
# get globals
|
|
187
|
+
globs.update(orig_func.__globals__ or {})
|
|
188
|
+
# get names of references
|
|
189
|
+
if not recurse:
|
|
190
|
+
func.update(orig_func.__code__.co_names)
|
|
191
|
+
else:
|
|
192
|
+
func.update(nestedglobals(orig_func.__code__))
|
|
193
|
+
# find globals for all entries of func
|
|
194
|
+
for key in func.copy(): #XXX: unnecessary...?
|
|
195
|
+
nested_func = globs.get(key)
|
|
196
|
+
if nested_func is orig_func:
|
|
197
|
+
#func.remove(key) if key in func else None
|
|
198
|
+
continue #XXX: globalvars(func, False)?
|
|
199
|
+
func.update(globalvars(nested_func, True, builtin))
|
|
200
|
+
elif iscode(func):
|
|
201
|
+
globs = vars(getmodule(sum)).copy() if builtin else {}
|
|
202
|
+
#globs.update(globals())
|
|
203
|
+
if not recurse:
|
|
204
|
+
func = func.co_names # get names
|
|
205
|
+
else:
|
|
206
|
+
orig_func = func.co_name # to stop infinite recursion
|
|
207
|
+
func = set(nestedglobals(func))
|
|
208
|
+
# find globals for all entries of func
|
|
209
|
+
for key in func.copy(): #XXX: unnecessary...?
|
|
210
|
+
if key is orig_func:
|
|
211
|
+
#func.remove(key) if key in func else None
|
|
212
|
+
continue #XXX: globalvars(func, False)?
|
|
213
|
+
nested_func = globs.get(key)
|
|
214
|
+
func.update(globalvars(nested_func, True, builtin))
|
|
215
|
+
else:
|
|
216
|
+
return {}
|
|
217
|
+
#NOTE: if name not in __globals__, then we skip it...
|
|
218
|
+
return dict((name,globs[name]) for name in func if name in globs)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def varnames(func):
|
|
222
|
+
"""get names of variables defined by func
|
|
223
|
+
|
|
224
|
+
returns a tuple (local vars, local vars referrenced by nested functions)"""
|
|
225
|
+
func = code(func)
|
|
226
|
+
if not iscode(func):
|
|
227
|
+
return () #XXX: better ((),())? or None?
|
|
228
|
+
return func.co_varnames, func.co_cellvars
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def baditems(obj, exact=False, safe=False): #XXX: obj=globals() ?
|
|
232
|
+
"""get items in object that fail to pickle"""
|
|
233
|
+
if not hasattr(obj,'__iter__'): # is not iterable
|
|
234
|
+
return [j for j in (badobjects(obj,0,exact,safe),) if j is not None]
|
|
235
|
+
obj = obj.values() if getattr(obj,'values',None) else obj
|
|
236
|
+
_obj = [] # can't use a set, as items may be unhashable
|
|
237
|
+
[_obj.append(badobjects(i,0,exact,safe)) for i in obj if i not in _obj]
|
|
238
|
+
return [j for j in _obj if j is not None]
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def badobjects(obj, depth=0, exact=False, safe=False):
|
|
242
|
+
"""get objects that fail to pickle"""
|
|
243
|
+
from dill import pickles
|
|
244
|
+
if not depth:
|
|
245
|
+
if pickles(obj,exact,safe): return None
|
|
246
|
+
return obj
|
|
247
|
+
return dict(((attr, badobjects(getattr(obj,attr),depth-1,exact,safe)) \
|
|
248
|
+
for attr in dir(obj) if not pickles(getattr(obj,attr),exact,safe)))
|
|
249
|
+
|
|
250
|
+
def badtypes(obj, depth=0, exact=False, safe=False):
|
|
251
|
+
"""get types for objects that fail to pickle"""
|
|
252
|
+
from dill import pickles
|
|
253
|
+
if not depth:
|
|
254
|
+
if pickles(obj,exact,safe): return None
|
|
255
|
+
return type(obj)
|
|
256
|
+
return dict(((attr, badtypes(getattr(obj,attr),depth-1,exact,safe)) \
|
|
257
|
+
for attr in dir(obj) if not pickles(getattr(obj,attr),exact,safe)))
|
|
258
|
+
|
|
259
|
+
def errors(obj, depth=0, exact=False, safe=False):
|
|
260
|
+
"""get errors for objects that fail to pickle"""
|
|
261
|
+
from dill import pickles, copy
|
|
262
|
+
if not depth:
|
|
263
|
+
try:
|
|
264
|
+
pik = copy(obj)
|
|
265
|
+
if exact:
|
|
266
|
+
assert pik == obj, \
|
|
267
|
+
"Unpickling produces %s instead of %s" % (pik,obj)
|
|
268
|
+
assert type(pik) == type(obj), \
|
|
269
|
+
"Unpickling produces %s instead of %s" % (type(pik),type(obj))
|
|
270
|
+
return None
|
|
271
|
+
except Exception:
|
|
272
|
+
import sys
|
|
273
|
+
return sys.exc_info()[1]
|
|
274
|
+
_dict = {}
|
|
275
|
+
for attr in dir(obj):
|
|
276
|
+
try:
|
|
277
|
+
_attr = getattr(obj,attr)
|
|
278
|
+
except Exception:
|
|
279
|
+
import sys
|
|
280
|
+
_dict[attr] = sys.exc_info()[1]
|
|
281
|
+
continue
|
|
282
|
+
if not pickles(_attr,exact,safe):
|
|
283
|
+
_dict[attr] = errors(_attr,depth-1,exact,safe)
|
|
284
|
+
return _dict
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
# EOF
|