pyflyby 1.10.4__cp311-cp311-macosx_11_0_arm64.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.
Files changed (53) hide show
  1. pyflyby/__init__.py +61 -0
  2. pyflyby/__main__.py +9 -0
  3. pyflyby/_autoimp.py +2228 -0
  4. pyflyby/_cmdline.py +591 -0
  5. pyflyby/_comms.py +221 -0
  6. pyflyby/_dbg.py +1383 -0
  7. pyflyby/_dynimp.py +154 -0
  8. pyflyby/_fast_iter_modules.cpython-311-darwin.so +0 -0
  9. pyflyby/_file.py +771 -0
  10. pyflyby/_flags.py +230 -0
  11. pyflyby/_format.py +186 -0
  12. pyflyby/_idents.py +227 -0
  13. pyflyby/_import_sorting.py +165 -0
  14. pyflyby/_importclns.py +658 -0
  15. pyflyby/_importdb.py +535 -0
  16. pyflyby/_imports2s.py +643 -0
  17. pyflyby/_importstmt.py +723 -0
  18. pyflyby/_interactive.py +2113 -0
  19. pyflyby/_livepatch.py +793 -0
  20. pyflyby/_log.py +107 -0
  21. pyflyby/_modules.py +646 -0
  22. pyflyby/_parse.py +1396 -0
  23. pyflyby/_py.py +2165 -0
  24. pyflyby/_saveframe.py +1145 -0
  25. pyflyby/_saveframe_reader.py +471 -0
  26. pyflyby/_util.py +458 -0
  27. pyflyby/_version.py +8 -0
  28. pyflyby/autoimport.py +20 -0
  29. pyflyby/etc/pyflyby/canonical.py +10 -0
  30. pyflyby/etc/pyflyby/common.py +27 -0
  31. pyflyby/etc/pyflyby/forget.py +10 -0
  32. pyflyby/etc/pyflyby/mandatory.py +10 -0
  33. pyflyby/etc/pyflyby/numpy.py +156 -0
  34. pyflyby/etc/pyflyby/std.py +335 -0
  35. pyflyby/importdb.py +19 -0
  36. pyflyby/libexec/pyflyby/colordiff +34 -0
  37. pyflyby/libexec/pyflyby/diff-colorize +148 -0
  38. pyflyby/share/emacs/site-lisp/pyflyby.el +112 -0
  39. pyflyby-1.10.4.data/scripts/collect-exports +76 -0
  40. pyflyby-1.10.4.data/scripts/collect-imports +58 -0
  41. pyflyby-1.10.4.data/scripts/find-import +38 -0
  42. pyflyby-1.10.4.data/scripts/prune-broken-imports +34 -0
  43. pyflyby-1.10.4.data/scripts/pyflyby-diff +34 -0
  44. pyflyby-1.10.4.data/scripts/reformat-imports +27 -0
  45. pyflyby-1.10.4.data/scripts/replace-star-imports +37 -0
  46. pyflyby-1.10.4.data/scripts/saveframe +299 -0
  47. pyflyby-1.10.4.data/scripts/tidy-imports +170 -0
  48. pyflyby-1.10.4.data/scripts/transform-imports +47 -0
  49. pyflyby-1.10.4.dist-info/METADATA +605 -0
  50. pyflyby-1.10.4.dist-info/RECORD +53 -0
  51. pyflyby-1.10.4.dist-info/WHEEL +6 -0
  52. pyflyby-1.10.4.dist-info/entry_points.txt +4 -0
  53. pyflyby-1.10.4.dist-info/licenses/LICENSE.txt +19 -0
@@ -0,0 +1,471 @@
1
+ """
2
+ pyflyby/_saveframe_reader.py
3
+
4
+ This module provides the ``SaveframeReader`` class, which is used to read data
5
+ saved by the ``saveframe`` utility.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ import pickle
12
+
13
+ from pyflyby._saveframe import ExceptionInfo, FrameMetadata
14
+
15
+ class SaveframeReader:
16
+ """
17
+ A class for reading data saved by the ``saveframe`` utility.
18
+
19
+ The ``saveframe`` utility saves data as a pickled Python dictionary.
20
+ Reading this raw data and extracting values of specific variables or metadata
21
+ fields can be complex.
22
+
23
+ The ``SaveframeReader`` class provides an easy and efficient way to read this
24
+ raw data and extract specific items. This class has a user-friendly ``repr``
25
+ for visualizing the data and provides various helpful methods to extract
26
+ different items.
27
+
28
+ **Usage Example:**
29
+
30
+ **Creating an instance**
31
+
32
+ First, create an instance of this class by passing the path of the file that
33
+ contains the ``saveframe`` data.
34
+
35
+ ::
36
+
37
+ >> from pyflyby import SaveframeReader
38
+ >> reader = SaveframeReader('/path/to/file')
39
+
40
+ **Extracting all available metadata fields**
41
+
42
+ To extract all available metadata fields, use the ``SaveframeReader.metadata``
43
+ property. Example:
44
+
45
+ ::
46
+
47
+ >> reader.metadata
48
+ ['frame_index', 'filename', 'lineno', 'function_name', 'function_qualname',
49
+ 'function_object', 'module_name', 'code', 'frame_identifier',
50
+ 'exception_string', 'exception_full_string', 'exception_class_name',
51
+ 'exception_class_qualname', 'exception_object', 'traceback']
52
+
53
+ **Extracting all stored local variables**
54
+
55
+ To extract the names of all local variables stored in the frames, use the
56
+ ``SaveframeReader.variables`` property. Example:
57
+
58
+ ::
59
+
60
+ >> reader.variables
61
+ {
62
+ 1: ['var1', 'var2', ...],
63
+ 2: ['var5', 'var8', 'var9', ...],
64
+ ...
65
+ }
66
+
67
+ **Extracting the value of a specific metadata field**
68
+
69
+ To extract the value of a specific metadata field, use the
70
+ `SaveframeReader.get_metadata` method. Example:
71
+
72
+ ::
73
+
74
+ >> reader.get_metadata("filename")
75
+ {1: '/dir1/mod1.py', 2: '/dir2/mod2.py', ...}
76
+
77
+ >> reader.get_metadata("filename", frame_idx=2)
78
+ '/dir2/mod2.py'
79
+
80
+ >> reader.get_metadata("exception_string")
81
+ "Error is raised"
82
+
83
+ **Extracting the value of specific local variables**
84
+
85
+ To extract the value of specific local variable(s), use the
86
+ `SaveframeReader.get_variables` method. Example:
87
+
88
+ ::
89
+
90
+ >> reader.get_variables('var1')
91
+ {2: var1_value2, 4: var1_value4}
92
+
93
+ >> reader.get_variables('var1', frame_idx=4)
94
+ var1_value4
95
+
96
+ >> reader.get_variables('var2')
97
+ var2_value3
98
+
99
+ >> reader.get_variables(['var1', 'var3'])
100
+ {2: {'var1': var1_value2, 'var3': var3_value2},
101
+ 4: {'var1': var1_value4}, 5: {'var3': var3_value5}}
102
+
103
+ >> reader.get_variables(['var1', 'var3'], frame_idx=2)
104
+ {'var1': var1_value2, 'var3': var3_value2}
105
+
106
+ Raw data can be extracted using ``SaveframeReader.data`` property.
107
+ """
108
+
109
+ def __init__(self, filename):
110
+ """
111
+ Initializes the ``SaveframeReader`` class.
112
+
113
+ :param filename:
114
+ The file path where the ``saveframe`` data is stored.
115
+ """
116
+ self._filename = filename
117
+ with open(filename, 'rb') as f:
118
+ self._data = pickle.load(f)
119
+ if not isinstance(self._data, dict):
120
+ raise ValueError(
121
+ f"The data in the file '{filename}' is of type "
122
+ f"'{type(self._data).__name__}', which is not valid saveframe "
123
+ "data.")
124
+
125
+
126
+ @property
127
+ def filename(self):
128
+ """
129
+ The file path where the ``saveframe`` data is stored.
130
+ """
131
+ return self._filename
132
+
133
+
134
+ @property
135
+ def data(self):
136
+ """
137
+ Returns the raw ``saveframe`` data as a Python dictionary.
138
+ """
139
+ return self._data
140
+
141
+
142
+ @property
143
+ def metadata(self):
144
+ """
145
+ Returns a list of all metadata items present in the data.
146
+
147
+ This includes both frame metadata and exception metadata. The returned
148
+ list contains the names of all metadata fields. For example:
149
+ ['frame_index', 'filename', ..., 'exception_object', 'traceback'].
150
+
151
+ To obtain the value of a specific metadata field, use the
152
+ `SaveframeReader.get_metadata` method.
153
+ """
154
+ metadata = []
155
+ metadata.extend([field for field in FrameMetadata.__dataclass_fields__])
156
+ metadata.extend([field for field in ExceptionInfo.__dataclass_fields__])
157
+ return metadata
158
+
159
+
160
+ @property
161
+ def variables(self):
162
+ """
163
+ Returns the local variables present in each frame.
164
+
165
+ The returned value is a dictionary where the keys are frame indices and
166
+ the values are lists of local variable names in those frames. For example:
167
+
168
+ ::
169
+
170
+ {
171
+ 1: ['variable1', 'variable2', ...],
172
+ 2: ['variable5', 'variable6', 'variable8'],
173
+ ...
174
+ }
175
+
176
+ To obtain the value of specific variable(s), use the
177
+ `SaveframeReader.get_variables` method.
178
+ """
179
+ frame_idx_to_variables_map = {}
180
+ for key_item in self._data:
181
+ if not isinstance(key_item, int):
182
+ continue
183
+ frame_idx_to_variables_map[key_item] = list(
184
+ self._data[key_item]['variables'].keys())
185
+ return frame_idx_to_variables_map
186
+
187
+
188
+ def get_metadata(self, metadata, *, frame_idx=None):
189
+ """
190
+ Retrieve the value of a specific metadata field.
191
+
192
+ **Example usage:**
193
+
194
+ ::
195
+
196
+ >> reader = SaveframeReader("/path/to/file")
197
+
198
+ >> reader.get_metadata("filename")
199
+ {1: '/dir1/mod1.py', 2: '/dir2/mod2.py', ...}
200
+
201
+ >> reader.get_metadata("filename", frame_idx=2)
202
+ '/dir2/mod2.py'
203
+
204
+ >> reader.get_metadata("exception_string")
205
+ "Error is raised"
206
+
207
+ :param metadata:
208
+ The metadata field for which to get the value.
209
+ :param frame_idx:
210
+ The index of the frame from which to get the metadata value. Default is
211
+ None, which means metadata from all frames is returned. This parameter
212
+ is only supported for frame metadata, not exception metadata.
213
+ :return:
214
+ - If ``frame_idx`` is None (default):
215
+ - If ``metadata`` is a frame metadata field, a dictionary is returned
216
+ with the frame index as the key and the metadata value as the value.
217
+ - If ``metadata`` is an exception metadata field, the value of the
218
+ metadata is returned.
219
+ - If ``frame_idx`` is specified:
220
+ - If ``metadata`` is a frame metadata field, the metadata value for
221
+ the specified frame is returned.
222
+ - If ``metadata`` is an exception metadata field, an error is raised.
223
+ """
224
+ # Sanity checks.
225
+ all_metadata_entries = self.metadata
226
+ if metadata not in all_metadata_entries:
227
+ raise ValueError(
228
+ f"Invalid metadata requested: {metadata!a}. Allowed metadata "
229
+ f"entries are: {all_metadata_entries}.")
230
+ exception_metadata = ([field for field in ExceptionInfo.__dataclass_fields__])
231
+ # Handle exception metadata.
232
+ if metadata in exception_metadata:
233
+ if frame_idx:
234
+ raise ValueError(
235
+ "'frame_idx' is not supported for querying exception "
236
+ f"metadata: {metadata!a}.")
237
+ return self._data[metadata]
238
+ # frame_idx is not passed.
239
+ if frame_idx is None:
240
+ frame_idx_to_metadata_value_map = {}
241
+ for key_item in self._data:
242
+ if key_item in exception_metadata:
243
+ continue
244
+ metadata_value = self._data[key_item][metadata]
245
+ # Unpickle the 'function_object' metadata value.
246
+ if metadata == "function_object":
247
+ try:
248
+ if not isinstance(metadata_value, str):
249
+ metadata_value = pickle.loads(metadata_value)
250
+ except Exception as err:
251
+ logging.warning("Can't unpickle the 'function_object' "
252
+ "value for frame: %a. Error: %s",
253
+ key_item, err)
254
+ metadata_value = (
255
+ f"Can't unpickle the 'function_object'. Error: {err}")
256
+ frame_idx_to_metadata_value_map[key_item] = metadata_value
257
+ return frame_idx_to_metadata_value_map
258
+
259
+ # frame_idx is passed.
260
+ if not isinstance(frame_idx, int):
261
+ raise TypeError(
262
+ "'frame_idx' must be of type 'int', not "
263
+ f"'{type(frame_idx).__name__}'.")
264
+ try:
265
+ metadata_value = self._data[frame_idx][metadata]
266
+ if metadata == "function_object":
267
+ try:
268
+ if not isinstance(metadata_value, str):
269
+ metadata_value = pickle.loads(metadata_value)
270
+ except Exception as err:
271
+ logging.warning("Can't unpickle the 'function_object' "
272
+ "value for frame: %a. Error: %s",
273
+ frame_idx, err)
274
+ return metadata_value
275
+ except KeyError:
276
+ allowed_frame_idx = list(
277
+ set(self._data.keys()) - set(exception_metadata))
278
+ raise ValueError(
279
+ f"Invalid value for 'frame_idx': '{frame_idx}'. Allowed values "
280
+ f"are: {allowed_frame_idx}.")
281
+
282
+
283
+ def get_variables(self, variables, *, frame_idx=None):
284
+ """
285
+ Retrieve the value of local variable(s) from specific frames.
286
+
287
+ **Example usage:**
288
+
289
+ ::
290
+
291
+ >> reader = SaveframeReader('/path/to/file')
292
+
293
+ >> reader.get_variables('var1')
294
+ {2: var1_value2, 4: var1_value4}
295
+
296
+ >> reader.get_variables('var1', frame_idx=4)
297
+ var1_value4
298
+
299
+ >> reader.get_variables(('var1',), frame_idx=4)
300
+ {'var1': var1_value4}
301
+
302
+ >> reader.get_variables('var2')
303
+ var2_value3 # 'var2' is only present in frame 3
304
+
305
+ >> reader.get_variables(['var1', 'var3'])
306
+ {2: {'var1': var1_value2, 'var3': var3_value2},
307
+ 4: {'var1': var1_value4}, 5: {'var3': var3_value5}}
308
+
309
+ >> reader.get_variables(['var1', 'var3'], frame_idx=2)
310
+ {'var1': var1_value2, 'var3': var3_value2}
311
+
312
+ :param variables:
313
+ One or more variable names for which to retrieve the values. You can
314
+ pass a single variable name as a string or a list / tuple of variable
315
+ names.
316
+
317
+ :param frame_idx:
318
+ The index of the frame from which to retrieve the value(s) of the
319
+ variable(s). Default is None, which means values from all frames are
320
+ returned.
321
+ :return:
322
+ - If ``frame_idx`` is None (default):
323
+ - For a single variable:
324
+ - A dictionary with frame indices as keys and variable values
325
+ as values.
326
+ - If the variable is present in only one frame, the value is
327
+ returned directly.
328
+ - For a list / tuple of variables:
329
+ - A dictionary with frame indices as keys and dictionaries as
330
+ values, where each inner dictionary contains the queried
331
+ variables and their values for that frame.
332
+ - If the queried variables are present in only one frame, a
333
+ dictionary of those variables and their values is returned.
334
+ - If ``frame_idx`` is specified:
335
+ - For a single variable:
336
+ - The value of the variable in the specified frame.
337
+ - If the variable is not present in that frame, an error is raised.
338
+ - For a list / tuple of variables:
339
+ - A dictionary with the variable names as keys and their values
340
+ as values, for the specified frame.
341
+ - If none of the queried variables are present in that frame,
342
+ an error is raised.
343
+ """
344
+ # Boolean to denote if variables are passed as a list or tuple.
345
+ variables_passed_as_list_or_tuple = False
346
+ # Sanity checks.
347
+ if isinstance(variables, (list, tuple)):
348
+ variables_passed_as_list_or_tuple = True
349
+ for variable in variables:
350
+ if not isinstance(variable, str):
351
+ raise TypeError(
352
+ f"Invalid type for variable name: {type(variable).__name__}. "
353
+ "Expected string type instead.")
354
+ elif isinstance(variables, str):
355
+ variables = (variables,)
356
+ else:
357
+ raise TypeError(
358
+ f"'variables' must either be a string or a list/tuple. "
359
+ f"Got '{type(variables).__name__}'.")
360
+ if len(variables) == 0:
361
+ raise ValueError("No 'variables' passed.")
362
+
363
+ def _get_variable_value_on_unpickle_error(err):
364
+ """
365
+ Get variable's value when it fails to unpickle due to error ``err``.
366
+ """
367
+ return f"Can't un-pickle the variable. Error: {err}"
368
+
369
+ # frame_idx is not passed.
370
+ if frame_idx is None:
371
+ frame_idx_to_variables_map = {}
372
+ for key_item in self._data:
373
+ if not isinstance(key_item, int):
374
+ continue
375
+ variables_map = self._data[key_item]['variables']
376
+ for variable in variables:
377
+ try:
378
+ variable_value = variables_map[variable]
379
+ except KeyError:
380
+ continue
381
+ try:
382
+ variable_value = pickle.loads(variable_value)
383
+ except Exception as err:
384
+ logging.warning(
385
+ "Can't un-pickle the value of variable %a for frame "
386
+ "%a. Error: %s", variable, key_item, err)
387
+ variable_value = _get_variable_value_on_unpickle_error(err)
388
+ if len(variables) == 1 and not variables_passed_as_list_or_tuple:
389
+ # Single variable is queried.
390
+ frame_idx_to_variables_map[key_item] = variable_value
391
+ else:
392
+ # Multiple variables are queried. The result would be
393
+ # a dict where keys would be the frame indices and values
394
+ # would the dicts containing the queried variables and
395
+ # their values for that frame.
396
+ if not key_item in frame_idx_to_variables_map:
397
+ frame_idx_to_variables_map[key_item] = {}
398
+ frame_idx_to_variables_map[key_item][variable] = variable_value
399
+ if not frame_idx_to_variables_map:
400
+ raise ValueError(f"Local variable(s) {variables} not found in "
401
+ "any of the saved frames.")
402
+ # If there is only 1 frame in the result, return the value directly.
403
+ if len(frame_idx_to_variables_map) == 1:
404
+ return frame_idx_to_variables_map.popitem()[1]
405
+ return frame_idx_to_variables_map
406
+
407
+ # frame_idx is passed.
408
+ if not isinstance(frame_idx, int):
409
+ raise TypeError(
410
+ "'frame_idx' must be of type 'int', not "
411
+ f"'{type(frame_idx).__name__}'.")
412
+ try:
413
+ variables_map = self._data[frame_idx]['variables']
414
+ except KeyError:
415
+ allowed_frame_idx = list(
416
+ set(self._data.keys()) - set(self.metadata))
417
+ raise ValueError(
418
+ f"Invalid value for 'frame_idx': '{frame_idx}'. Allowed values "
419
+ f"are: {allowed_frame_idx}.")
420
+ variable_key_to_value_map = {}
421
+ for variable in variables:
422
+ try:
423
+ variable_value = variables_map[variable]
424
+ except KeyError:
425
+ continue
426
+ try:
427
+ variable_value = pickle.loads(variable_value)
428
+ except Exception as err:
429
+ logging.warning(
430
+ "Can't un-pickle the value of variable %a for frame "
431
+ "%a. Error: %s", variable, frame_idx, err)
432
+ if len(variables) > 1:
433
+ variable_value = _get_variable_value_on_unpickle_error(err)
434
+ if len(variables) == 1 and not variables_passed_as_list_or_tuple:
435
+ # Single variable is queried. Directly return the value.
436
+ return variable_value
437
+ variable_key_to_value_map[variable] = variable_value
438
+ if not variable_key_to_value_map:
439
+ raise ValueError(f"Local variable(s) {variables} not found in "
440
+ f"frame {frame_idx}")
441
+ return variable_key_to_value_map
442
+
443
+
444
+ def __str__(self):
445
+ frames_info = []
446
+ for frame_idx, frame_data in self._data.items():
447
+ if isinstance(frame_idx, int):
448
+ frame_info = (
449
+ f"Frame {frame_idx}:\n"
450
+ f" Filename: '{frame_data.get('filename')}'\n"
451
+ f" Line Number: {frame_data.get('lineno')}\n"
452
+ f" Function: {frame_data.get('function_qualname')}\n"
453
+ f" Module: {frame_data.get('module_name')}\n"
454
+ f" Frame ID: '{frame_data.get('frame_identifier')}'\n"
455
+ f" Code: {frame_data.get('code')}\n"
456
+ f" Variables: {list(frame_data.get('variables', {}).keys())}\n"
457
+ )
458
+ frames_info.append(frame_info)
459
+
460
+ exception_info = (
461
+ f"Exception:\n"
462
+ f" Full String: {self._data.get('exception_full_string')}\n"
463
+ f" String: {self._data.get('exception_string')}\n"
464
+ f" Class Name: {self._data.get('exception_class_name')}\n"
465
+ f" Qualified Name: {self._data.get('exception_class_qualname')}\n"
466
+ )
467
+
468
+ return "Frames:\n" + "\n".join(frames_info) + "\n" + exception_info
469
+
470
+ def __repr__(self):
471
+ return f"{self.__class__.__name__}(\nfilename: {self._filename!a} \n\n{str(self)})"