-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathapi.py
More file actions
264 lines (210 loc) · 9.25 KB
/
api.py
File metadata and controls
264 lines (210 loc) · 9.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
from __future__ import absolute_import, division, print_function
import sys
import traceback
from collections import OrderedDict
from qtpy.QtWidgets import QApplication, QMainWindow
import larray as la
from larray_editor.editor import REOPEN_LAST_FILE, MappingEditor, ArrayEditor
__all__ = ['view', 'edit', 'compare', 'REOPEN_LAST_FILE']
def qapplication():
return QApplication(sys.argv)
def find_names(obj, depth=0):
"""Return all names an object is bound to.
Parameters
----------
obj : object
the object to find names for.
depth : int
depth of call frame to inspect. 0 is where find_names was called,
1 the caller of find_names, etc.
Returns
-------
list of str
all names obj is bound to, sorted alphabetically. Can be [] if we
computed an array just to view it.
"""
# noinspection PyProtectedMember
l = sys._getframe(depth + 1).f_locals
names = [k for k, v in l.items() if v is obj]
if any(not name.startswith('_') for name in names):
names = [name for name in names if not name.startswith('_')]
return sorted(names)
def get_title(obj, depth=0, maxnames=3):
"""Return a title for an object (a combination of the names it is bound to).
Parameters
----------
obj : object
the object to find a title for.
depth : int
depth of call frame to inspect. 0 is where get_title was called,
1 the caller of get_title, etc.
Returns
-------
str
title for obj. This can be '' if we computed an array just to view it.
"""
names = find_names(obj, depth=depth + 1)
# names can be == []
# eg. view(arr['M'])
if len(names) > maxnames:
names = names[:maxnames] + ['...']
return ', '.join(names)
# TODO: update doccstring
def edit(obj=None, title='', minvalue=None, maxvalue=None, readonly=False, depth=0):
"""
Opens a new editor window.
Parameters
----------
obj : (dict of) np.ndarray, LArray, Session, dict, str or REOPEN_LAST_FILE, optional
Object(s) to visualize. If string, array(s) will be loaded from the file given as argument.
Passing the constant REOPEN_LAST_FILE loads the last opened file.
Defaults to the collection of all local variables where the function was called.
title : str, optional
Title for the current object. Defaults to the name of the first object found in the caller namespace which
corresponds to `obj` (it will use a combination of the 3 first names if several names correspond to the same
object).
minvalue : scalar, optional
Minimum value allowed.
maxvalue : scalar, optional
Maximum value allowed.
readonly : bool, optional
Whether or not editing array values is forbidden. Defaults to False.
depth : int, optional
Stack depth where to look for variables. Defaults to 0 (where this function was called).
Examples
--------
>>> a1 = ndtest(3) # doctest: +SKIP
>>> a2 = ndtest(3) + 1 # doctest: +SKIP
>>> # will open an editor with all the arrays available at this point
>>> # (a1 and a2 in this case)
>>> edit() # doctest: +SKIP
>>> # will open an editor for a1 only
>>> edit(a1) # doctest: +SKIP
"""
install_except_hook()
_app = QApplication.instance()
if _app is None:
_app = qapplication()
_app.setOrganizationName("LArray")
_app.setApplicationName("Viewer")
parent = None
else:
parent = _app.activeWindow()
if obj is None:
caller_frame = sys._getframe(depth + 1)
global_vars = caller_frame.f_globals
local_vars = caller_frame.f_locals
obj = OrderedDict()
obj.update([(k, global_vars[k]) for k in sorted(global_vars.keys())])
obj.update([(k, local_vars[k]) for k in sorted(local_vars.keys())])
if hasattr(obj, 'keys'):
obj = OrderedDict(obj)
if not title and obj is not REOPEN_LAST_FILE:
title = get_title(obj, depth=depth + 1)
if obj is REOPEN_LAST_FILE or isinstance(obj, (str, OrderedDict)):
dlg = MappingEditor(parent)
assert minvalue is None and maxvalue is None
setup_ok = dlg.setup_and_check(obj, title=title, readonly=readonly)
else:
dlg = ArrayEditor(parent)
setup_ok = dlg.setup_and_check(obj, title=title, readonly=readonly, minvalue=minvalue, maxvalue=maxvalue)
if setup_ok:
dlg.show()
_app.exec_()
restore_except_hook()
# TODO: update doccstring
def view(obj=None, title='', depth=0):
"""
Opens a new viewer window. Arrays are loaded in readonly mode and their content cannot be modified.
Parameters
----------
obj : (dict of) np.ndarray, LArray, Session, dict, str or REOPEN_LAST_FILE, optional
Object(s) to visualize. If string, array(s) will be loaded from the file given as argument.
Passing the constant REOPEN_LAST_FILE loads the last opened file.
Defaults to the collection of all local variables where the function was called.
title : str, optional
Title for the current object. Defaults to the name of the first object found in the caller namespace which
corresponds to `obj` (it will use a combination of the 3 first names if several names correspond to the same
object).
depth : int, optional
Stack depth where to look for variables. Defaults to 0 (where this function was called).
Examples
--------
>>> a1 = ndtest(3) # doctest: +SKIP
>>> a2 = ndtest(3) + 1 # doctest: +SKIP
>>> # will open a viewer showing all the arrays available at this point
>>> # (a1 and a2 in this case)
>>> view() # doctest: +SKIP
>>> # will open a viewer showing only a1
>>> view(a1) # doctest: +SKIP
"""
edit(obj, title=title, readonly=True, depth=depth + 1)
def compare(*args, **kwargs):
"""
Opens a new comparator window, comparing arrays or sessions.
Parameters
----------
*args : LArrays or Sessions
Arrays or sessions to compare.
title : str, optional
Title for the window. Defaults to ''.
names : list of str, optional
Names for arrays or sessions being compared. Defaults to the name of the first objects found in the caller
namespace which correspond to the passed objects.
depth : int, optional
Stack depth where to look for variables. Defaults to 0 (where this function was called).
Examples
--------
>>> a1 = ndtest(3) # doctest: +SKIP
>>> a2 = ndtest(3) + 1 # doctest: +SKIP
>>> compare(a1, a2, title='first comparison') # doctest: +SKIP
>>> compare(a1 + 1, a2, title='second comparison', names=['a1+1', 'a2']) # doctest: +SKIP
"""
install_except_hook()
title = kwargs.pop('title', '')
names = kwargs.pop('names', None)
depth = kwargs.pop('depth', 0)
_app = QApplication.instance()
if _app is None:
_app = qapplication()
parent = None
else:
parent = _app.activeWindow()
if any(isinstance(a, la.Session) for a in args):
from larray_editor.comparator import SessionComparator
dlg = SessionComparator(parent)
default_name = 'session'
else:
from larray_editor.comparator import ArrayComparator
dlg = ArrayComparator(parent)
default_name = 'array'
def get_name(i, obj, depth=0):
obj_names = find_names(obj, depth=depth + 1)
return obj_names[0] if obj_names else '%s %d' % (default_name, i)
if names is None:
# depth + 2 because of the list comprehension
names = [get_name(i, a, depth=depth + 2) for i, a in enumerate(args)]
else:
assert isinstance(names, list) and len(names) == len(args)
if dlg.setup_and_check(args, names=names, title=title):
dlg.show()
_app.exec_()
restore_except_hook()
_orig_except_hook = sys.excepthook
def _qt_except_hook(type, value, tback):
# only print the exception and do *not* exit the program
traceback.print_exception(type, value, tback)
def install_except_hook():
sys.excepthook = _qt_except_hook
def restore_except_hook():
sys.excepthook = _orig_except_hook
_orig_display_hook = sys.displayhook
def _qt_display_hook(value):
if isinstance(value, la.LArray):
view(value)
else:
_orig_display_hook(value)
def install_display_hook():
sys.displayhook = _qt_display_hook
def restore_display_hook():
sys.displayhook = _orig_display_hook