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,299 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Utility to save information for debugging / reproducing an issue.
4
+
5
+ Usage:
6
+ If you have a script or command that is currently failing due to an issue
7
+ originating from upstream code, and you cannot share your private code as
8
+ a reproducer, use this utility to save relevant information to a file (e.g.,
9
+ error frames specific to the upstream codebase). Share the generated file
10
+ with the upstream team, enabling them to reproduce and diagnose the issue
11
+ independently.
12
+
13
+ Information saved in the file:
14
+ This utility captures and saves error stack frames to a file. It includes the
15
+ values of local variables from each stack frame, as well as metadata about each
16
+ frame and the exception raised by the user's script or command. Following is the
17
+ sample structure of the info saved in the file:
18
+
19
+ {
20
+ # 5th frame from the bottom
21
+ 5: {
22
+ 'frame_index': 5,
23
+ 'filename': '/path/to/file.py',
24
+ 'lineno': 3423,
25
+ 'function_name': 'func1',
26
+ 'function_qualname': 'FooClass.func1',
27
+ 'function_object': <pickled object>,
28
+ 'module_name': '<frame_module>'
29
+ 'frame_identifier': '/path/to/file.py,3423,func1',
30
+ 'code': '... python code line ...'
31
+ 'variables': {'local_variable1': <pickled value>, 'local_variable2': <pickled value>, ...}
32
+ },
33
+ # 17th frame from the bottom
34
+ 17: {
35
+ 'frame_index': 17,
36
+ ...
37
+ },
38
+ ...
39
+ 'exception_full_string': f'{exc.__class.__name__}: {exc}'
40
+ 'exception_object': exc,
41
+ 'exception_string': str(exc),
42
+ 'exception_class_name': exc.__class__.__name__,
43
+ 'exception_class_qualname': exc.__class__.__qualname__,
44
+ 'traceback': '(multiline traceback)
45
+ }
46
+
47
+ NOTE:
48
+ - The above data gets saved in the file in pickled form.
49
+ - In the above data, the key of each frame's entry is the index of that frame
50
+ from the bottom of the error stack trace. So the first frame from the bottom
51
+ (the error frame) has index 1, and so on.
52
+ - 'variables' key in each frame's entry stores the local variables of that frame.
53
+ - The 'exception_object' key stores the actual exception object but without
54
+ the __traceback__ info (for security reasons).
55
+
56
+ Example Usage:
57
+
58
+ Let's say your script / command is raising an error with the following traceback:
59
+
60
+ File "dir/__init__.py", line 6, in init_func1
61
+ func1()
62
+ File "dir/mod1.py", line 14, in func1
63
+ func2()
64
+ File "dir/mod1.py", line 9, in func2
65
+ obj.func2()
66
+ File "dir/pkg1/mod2.py", line 10, in func2
67
+ func3()
68
+ File "dir/pkg1/pkg2/mod3.py", line 6, in func3
69
+ raise ValueError("Error is raised")
70
+ ValueError: Error is raised
71
+
72
+ => To save the last frame (the error frame) in file '/path/to/file', use:
73
+ $ saveframe --filename=/path/to/file <script_or_command_to_run>
74
+
75
+ => To save a specific frame like `File "dir/mod1.py", line 9, in func2`, use:
76
+ $ saveframe --filename=/path/to/file --frames=mod1.py:9:func2 <script_or_command_to_run>
77
+
78
+ => To save the first 3 frames from the bottom, use:
79
+ $ saveframe --frames=3 <script_or_command_to_run>
80
+
81
+ => To save all the frames from 'mod1.py' and 'mod2.py' files, use:
82
+ $ saveframe --filename=/path/to/file --frames=mod1.py::,mod2.py:: <script_or_command_to_run>
83
+
84
+ => To save a range of frames from 'mod1.py' to 'mod3.py', use:
85
+ $ saveframe --frames=mod1.py::..mod3.py:: <script_or_command_to_run>
86
+
87
+ => To save a range of frames from '__init__.py' till the last frame, use:
88
+ $ saveframe --frames=__init__.py::.. <script_or_command_to_run>
89
+
90
+ => To only save local variables 'var1' and 'var2' from the frames, use:
91
+ $ saveframe --frames=frames_to_save --variables=var1,var2 <script_or_command_to_run>
92
+
93
+ => To exclude local variables 'var1' and 'var2' from the frames, use:
94
+ $ saveframe --frames=frames_to_save --exclude_variables=var1,var2 <script_or_command_to_run>
95
+
96
+ For interactive use cases, checkout pyflyby.saveframe function.
97
+ """
98
+ from __future__ import annotations
99
+
100
+ # Save an unspoiled copy of globals for running the user program.
101
+ globals_cpy = globals().copy()
102
+
103
+ import argparse
104
+ import os
105
+ import sys
106
+
107
+ from pyflyby._saveframe import (_SAVEFRAME_LOGGER,
108
+ _save_frames_and_exception_info_to_file,
109
+ _validate_saveframe_arguments)
110
+
111
+
112
+ def getargs():
113
+ """
114
+ Parse the command-line arguments.
115
+ """
116
+ parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
117
+ description=__doc__,
118
+ prog=os.path.basename(sys.argv[0]))
119
+ parser.add_argument(
120
+ "--filename", default=None,
121
+ help="File path in which to save the frame information. If this file "
122
+ "already exists, it will be overwritten; otherwise, a new file will "
123
+ "be created with permission mode '0o644'\nDefault behavior: "
124
+ "If --filename is not passed, the info gets saved in the "
125
+ "'saveframe.pkl' file in the current working directory."
126
+ )
127
+ parser.add_argument(
128
+ "--frames", default=None,
129
+ help="Error stack frames to save.\n"
130
+ "Default behavior: If --frames is not passed, the first frame from "
131
+ "the bottom (the error frame) is saved.\n\n"
132
+ "A single frame follows the format "
133
+ "'filename:line_no:function_name', where:\n"
134
+ " - filename: The file path or a regex pattern matching the file "
135
+ "path (displayed in the stack trace) of that error frame.\n"
136
+ " - line_no (Optional): The code line number (displayed in the "
137
+ "stack trace) of that error frame.\n"
138
+ " - function_name (Optional): The function name (displayed in "
139
+ "the stack trace) of that error frame.\n\n"
140
+ "Partial frames are also supported where line_no and/or function_name "
141
+ "can be omitted:\n"
142
+ " - 'filename::' -> Includes all the frames that matches the filename\n"
143
+ " - 'filename:line_no:' -> Include all the frames that matches "
144
+ "specific line in any function in the filename\n"
145
+ " - 'filename::function_name' -> Include all the frames that matches "
146
+ "any line in the specific function in the filename\n\n"
147
+ "Following formats are supported to pass the frames:\n\n"
148
+ "1. Single frame:\n"
149
+ " --frames=frame\n"
150
+ " Example: --frames=/path/to/file.py:24:some_func\n"
151
+ " Includes only the specified frame.\n\n"
152
+ "2. Multiple frames:\n"
153
+ " --frames=frame1,frame2,...\n"
154
+ " Example: --frames=/dir/foo.py:45:,.*/dir2/bar.py:89:caller\n"
155
+ " Includes all specified frames.\n\n"
156
+ "3. Range of frames:\n"
157
+ " --frames=first_frame..last_frame\n"
158
+ " Example: --frames=/dir/foo.py:45:get_foo../dir3/blah.py:23:myfunc\n"
159
+ " Includes all the frames from first_frame to last_frame (both inclusive).\n\n"
160
+ "4. Range from first_frame to bottom:\n"
161
+ " --frames=first_frame..\n"
162
+ " Example: --frames=/dir/foo.py:45:get_foo..\n"
163
+ " Includes all the frames from first_frame to the bottom of the stack trace.\n\n"
164
+ "5. Number of Frames from Bottom:\n"
165
+ " --frames=num\n"
166
+ " Example: --frames=5\n"
167
+ " Includes the first 'num' frames from the bottom of the stack trace."
168
+ )
169
+ parser.add_argument(
170
+ "--variables", default=None,
171
+ help="Local variables to include in each frame. Allowed format:\n"
172
+ "--variables=var1,var2,var3...\nExample: --variables=foo,bar\n\n"
173
+ "Default behavior: If --variables is not passed, save all the local "
174
+ "variables of the included frames."
175
+ )
176
+ parser.add_argument(
177
+ "--exclude_variables", default=None,
178
+ help="Local variables to exclude from each frame. Allowed format:\n"
179
+ "--exclude_variables=var1,var2,var3...\nExample: "
180
+ "--exclude_variables=foo,bar\n\n"
181
+ "Default behavior: If --exclude_variables is not passed, save all "
182
+ "the local variables of the included frames as per --variables."
183
+ )
184
+ parser.add_argument(
185
+ "command", default=argparse.SUPPRESS, nargs=argparse.REMAINDER,
186
+ help="User's script / command to execute.")
187
+ args = parser.parse_args()
188
+ return args
189
+
190
+
191
+ def which(program):
192
+ """
193
+ Find the complete path of the ``program``.
194
+
195
+ :param program:
196
+ Program for which to find the complete path.
197
+ :return:
198
+ Complete path of the program.
199
+ """
200
+ if os.access(program, os.R_OK):
201
+ return program
202
+
203
+ fpath, fname = os.path.split(program)
204
+ if fpath:
205
+ if os.access(fpath, os.R_OK):
206
+ return program
207
+ else:
208
+ for path in os.environ["PATH"].split(os.pathsep):
209
+ exe_file = os.path.join(path, program)
210
+ if os.access(exe_file, os.X_OK):
211
+ return exe_file
212
+
213
+ return None
214
+
215
+
216
+ def execfile(filepath):
217
+ """
218
+ Execute the script stored in ``filepath``.
219
+
220
+ :param filepath:
221
+ Path of the script to execute.
222
+ """
223
+ globals_cpy.update({
224
+ "__file__": filepath,
225
+ "__name__": "__main__",
226
+ })
227
+ with open(filepath, 'rb') as file:
228
+ exec(compile(file.read(), filepath, 'exec'), globals_cpy)
229
+
230
+
231
+ def run_program(command):
232
+ """
233
+ Run a program.
234
+
235
+ :param command:
236
+ List containing the command to run.
237
+ """
238
+ if len(command) == 0:
239
+ raise SystemExit("Error: Please pass a valid script / command to run!")
240
+ if command[0] == '-c':
241
+ if len(command) == 1:
242
+ raise SystemExit("Error: Please pass a valid script / command to run!")
243
+ # Set sys.argv. Mimic regular python -c by dropping the code but
244
+ # keeping the rest.
245
+ sys.argv = ['-c'] + command[2:]
246
+ globals_cpy['__file__'] = None
247
+ # Evaluate the command line code.
248
+ code = compile(command[1], "<stdin>", "exec")
249
+ eval(code)
250
+ else:
251
+ prog = which(command[0])
252
+ if not prog:
253
+ raise SystemExit(f"Error: Can't find the script / command: {command[0]!r}")
254
+
255
+ # Set sys.argv to mimic the command execution.
256
+ sys.argv = command
257
+ sys.path.insert(0, os.path.dirname(os.path.realpath(prog)))
258
+ execfile(prog)
259
+
260
+
261
+ def main():
262
+ """
263
+ Main body of the script.
264
+ """
265
+ args = getargs()
266
+ # Validate the arguments.
267
+ filename, frames, variables, exclude_variables = _validate_saveframe_arguments(
268
+ filename=args.filename, frames=args.frames, variables=args.variables,
269
+ exclude_variables=args.exclude_variables, utility='script')
270
+ command = args.command
271
+ command_string = ' '.join(command)
272
+
273
+ if len(command) == 0:
274
+ raise SystemExit("Error: Please pass a valid script / command to run!")
275
+ if (command[0] in ['python', 'python3'] or command[0].endswith('/python')
276
+ or command[0].endswith('/python3')):
277
+ del command[0]
278
+
279
+ # Run the user script / command. Explicitly catch Exception and
280
+ # KeyboardInterrupt rather than BaseException, since we don't want to
281
+ # catch SystemExit.
282
+ try:
283
+ _SAVEFRAME_LOGGER.info("Executing the program: %a", command_string)
284
+ run_program(command)
285
+ except (Exception, KeyboardInterrupt) as err:
286
+ _SAVEFRAME_LOGGER.info(
287
+ "Saving frames and metadata info for the exception: %a", err)
288
+ # Save the frames and metadata info to the file.
289
+ _save_frames_and_exception_info_to_file(
290
+ filename=filename, frames=frames, variables=variables,
291
+ exclude_variables=exclude_variables,
292
+ exception_obj=err)
293
+ else:
294
+ raise SystemExit(
295
+ f"Error: No exception is raised by the program: {command_string!a}")
296
+
297
+
298
+ if __name__ == '__main__':
299
+ main()
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ tidy-imports *.py
4
+ tidy-imports < foo.py
5
+
6
+ Automatically improves python import statements.
7
+
8
+ - Adds missing imports and mandatory imports.
9
+ - Removes unused imports.
10
+ - Nicely formats imports (sorts, aligns, wraps).
11
+
12
+ If filenames are given on the command line, rewrites them. Otherwise, if
13
+ stdin is not a tty, read from stdin and write to stdout.
14
+
15
+ Only top-level import statements are touched.
16
+
17
+ """
18
+
19
+ # pyflyby/tidy-imports
20
+ # Copyright (C) 2011, 2012, 2014 Karl Chen.
21
+ # License: MIT http://opensource.org/licenses/MIT
22
+
23
+
24
+ from pyflyby._cmdline import (_get_pyproj_toml_config, hfmt,
25
+ parse_args, process_actions)
26
+ from pyflyby._import_sorting import sort_imports
27
+ from pyflyby._imports2s import (canonicalize_imports,
28
+ fix_unused_and_missing_imports,
29
+ replace_star_imports,
30
+ transform_imports)
31
+ from pyflyby._parse import PythonBlock
32
+
33
+
34
+ def _addopts(parser):
35
+ """
36
+ Callbacks to the parser to fill in extra options.
37
+ """
38
+ parser.add_option('--add-missing',
39
+ default=True, action='store_true',
40
+ help=hfmt('''
41
+ (Default) Add missing imports.'''))
42
+ parser.add_option('--no-add-missing', dest='add_missing',
43
+ default=True, action='store_false',
44
+ help=hfmt('''
45
+ Don't add missing imports.'''))
46
+ parser.add_option('--remove-unused',
47
+ default="AUTOMATIC", action='store_true',
48
+ help=hfmt('''
49
+ Remove unused imports
50
+ (default unless filename == __init__.py).'''))
51
+ parser.add_option('--no-remove-unused', dest='remove_unused',
52
+ action='store_false',
53
+ help=hfmt('''
54
+ Don't remove unused imports
55
+ (default if filename == __init__.py).'''))
56
+ parser.add_option('--add-mandatory',
57
+ default=True, action='store_true',
58
+ help=hfmt('''
59
+ (Default) Add mandatory imports.'''))
60
+ parser.add_option('--no-add-mandatory', dest='add_mandatory',
61
+ default=True, action='store_false',
62
+ help=hfmt('''
63
+ Don't add mandatory imports.'''))
64
+ parser.add_option('--replace-star-imports',
65
+ default=False, action='store_true',
66
+ help=hfmt('''
67
+ Replace 'from foo.bar import *' with full list
68
+ of imports before removing unused imports.'''))
69
+ parser.add_option('--no-replace-star-imports',
70
+ dest='replace_star_imports',
71
+ action='store_false',
72
+ help=hfmt('''
73
+ (Default) Don't replace 'from foo.bar import
74
+ *'.'''))
75
+ parser.add_option('--canonicalize',
76
+ default=True, action='store_true',
77
+ help=hfmt('''
78
+ (Default) Replace imports with canonical
79
+ equivalent imports, according to database.'''))
80
+ parser.add_option('--experimental-sort-imports',
81
+ default=False, action='store_true',
82
+ help=hfmt('''
83
+ experimental import sorting'''))
84
+ parser.add_option('--no-canonicalize', dest='canonicalize',
85
+ default=True, action='store_false',
86
+ help=hfmt('''
87
+ Don't canonicalize imports.'''))
88
+ parser.add_option('--exclude', type='string', dest='exclude',
89
+ action='append', help=hfmt('Files to exclude from formatting.'))
90
+
91
+
92
+ def transform_callback(option, opt_str, value, group):
93
+ k, v = value.split("=", 1)
94
+ group.values.transformations[k] = v
95
+ parser.add_option("--transform", action='callback',
96
+ type="string", callback=transform_callback,
97
+ metavar="OLD=NEW",
98
+ dest="transformations", default={},
99
+ help=hfmt('''
100
+ Replace OLD with NEW in imports.
101
+ May be specified multiple times.'''))
102
+ def no_add_callback(option, opt_str, value, group):
103
+ group.values.add_missing = False
104
+ group.values.add_mandatory = False
105
+ parser.add_option('--no-add', action='callback',
106
+ callback=no_add_callback,
107
+ help=hfmt('''
108
+ Equivalent to --no-add-missing
109
+ --no-add-mandatory.'''))
110
+ def main() -> None:
111
+
112
+ config = _get_pyproj_toml_config()
113
+ if config:
114
+ default_config = config.get('tool', {}).get('pyflyby',{})
115
+ else:
116
+ default_config = {}
117
+
118
+ def _add_opts_and_defaults(parser):
119
+ _addopts(parser)
120
+ parser.set_defaults(**default_config)
121
+
122
+ options, args = parse_args(
123
+ _add_opts_and_defaults,
124
+ import_format_params=True,
125
+ modify_action_params=True,
126
+ )
127
+
128
+ def modify(block:PythonBlock) -> PythonBlock:
129
+ if options.transformations:
130
+ block = transform_imports(block, options.transformations,
131
+ params=options.params)
132
+ if options.replace_star_imports:
133
+ block = replace_star_imports(block, params=options.params)
134
+ block = fix_unused_and_missing_imports(
135
+ block, params=options.params,
136
+ add_missing=options.add_missing,
137
+ remove_unused=options.remove_unused,
138
+ add_mandatory=options.add_mandatory,
139
+ )
140
+ # TODO: disable sorting until we figure out #287
141
+ # https://github.com/deshaw/pyflyby/issues/287
142
+
143
+ # here we get a (single?) PythonBlock, we can access each statement with
144
+ # >>> block.statements
145
+ # and each statement can have a:
146
+ # is_import
147
+ # or
148
+ # is_comment or blank
149
+
150
+ # TODO: we do Python(str(...)) in order to unparse-reparse and get proper ast node numbers.
151
+ if options.experimental_sort_imports:
152
+ sorted_imports = PythonBlock(str(sort_imports(block)))
153
+ else:
154
+ sorted_imports = block
155
+ if options.canonicalize:
156
+ cannonical_imports = canonicalize_imports(sorted_imports, params=options.params)
157
+ else:
158
+ cannonical_imports = sorted_imports
159
+ return cannonical_imports
160
+
161
+ cmdline_exclude = getattr(options, "exclude")
162
+ process_actions(
163
+ args,
164
+ options.actions, modify,
165
+ exclude=default_config.get('tidy-imports', {}).get('exclude', []) + (cmdline_exclude if cmdline_exclude else [])
166
+ )
167
+
168
+
169
+ if __name__ == '__main__':
170
+ main()
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ transform-imports --transform aa.bb=xx.yy *.py
4
+ transform-imports --transform aa.bb=xx.yy < foo.py
5
+
6
+ Transforms::
7
+ from aa.bb.cc import dd, ee
8
+ from aa import bb
9
+ to::
10
+ from xx.yy.cc import dd, ee
11
+ from xx import yy as bb
12
+
13
+ If filenames are given on the command line, rewrites them. Otherwise, if
14
+ stdin is not a tty, read from stdin and write to stdout.
15
+
16
+ """
17
+
18
+ # pyflyby/transform-imports
19
+ # Copyright (C) 2014 Karl Chen.
20
+ # License: MIT http://opensource.org/licenses/MIT
21
+
22
+
23
+ from pyflyby._cmdline import hfmt, parse_args, process_actions
24
+ from pyflyby._imports2s import transform_imports
25
+
26
+
27
+ def main():
28
+ transformations = {}
29
+ def addopts(parser):
30
+ def callback(option, opt_str, value, group):
31
+ k, v = value.split("=", 1)
32
+ transformations[k] = v
33
+ parser.add_option("--transform", action='callback',
34
+ type="string", callback=callback,
35
+ metavar="OLD=NEW",
36
+ help=hfmt('''
37
+ Replace OLD with NEW in imports.
38
+ May be specified multiple times.'''))
39
+ options, args = parse_args(
40
+ addopts, import_format_params=True, modify_action_params=True)
41
+ def modify(x):
42
+ return transform_imports(x, transformations, params=options.params)
43
+ process_actions(args, options.actions, modify)
44
+
45
+
46
+ if __name__ == '__main__':
47
+ main()