pyflyby 1.9.4__py3-none-any.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.

Potentially problematic release.


This version of pyflyby might be problematic. Click here for more details.

Files changed (54) hide show
  1. pyflyby/__init__.py +56 -0
  2. pyflyby/__main__.py +9 -0
  3. pyflyby/_autoimp.py +2114 -0
  4. pyflyby/_cmdline.py +531 -0
  5. pyflyby/_comms.py +221 -0
  6. pyflyby/_dbg.py +1339 -0
  7. pyflyby/_docxref.py +379 -0
  8. pyflyby/_file.py +738 -0
  9. pyflyby/_flags.py +230 -0
  10. pyflyby/_format.py +182 -0
  11. pyflyby/_idents.py +233 -0
  12. pyflyby/_import_sorting.py +165 -0
  13. pyflyby/_importclns.py +642 -0
  14. pyflyby/_importdb.py +588 -0
  15. pyflyby/_imports2s.py +639 -0
  16. pyflyby/_importstmt.py +662 -0
  17. pyflyby/_interactive.py +2605 -0
  18. pyflyby/_livepatch.py +793 -0
  19. pyflyby/_log.py +199 -0
  20. pyflyby/_modules.py +515 -0
  21. pyflyby/_parse.py +1441 -0
  22. pyflyby/_py.py +2078 -0
  23. pyflyby/_util.py +459 -0
  24. pyflyby/_version.py +7 -0
  25. pyflyby/autoimport.py +20 -0
  26. pyflyby/importdb.py +19 -0
  27. pyflyby-1.9.4.data/data/etc/pyflyby/canonical.py +10 -0
  28. pyflyby-1.9.4.data/data/etc/pyflyby/common.py +27 -0
  29. pyflyby-1.9.4.data/data/etc/pyflyby/forget.py +10 -0
  30. pyflyby-1.9.4.data/data/etc/pyflyby/mandatory.py +10 -0
  31. pyflyby-1.9.4.data/data/etc/pyflyby/numpy.py +156 -0
  32. pyflyby-1.9.4.data/data/etc/pyflyby/std.py +335 -0
  33. pyflyby-1.9.4.data/data/libexec/pyflyby/colordiff +34 -0
  34. pyflyby-1.9.4.data/data/libexec/pyflyby/diff-colorize +148 -0
  35. pyflyby-1.9.4.data/data/share/doc/pyflyby/LICENSE.txt +23 -0
  36. pyflyby-1.9.4.data/data/share/doc/pyflyby/TODO.txt +115 -0
  37. pyflyby-1.9.4.data/data/share/doc/pyflyby/testing.txt +13 -0
  38. pyflyby-1.9.4.data/data/share/emacs/site-lisp/pyflyby.el +108 -0
  39. pyflyby-1.9.4.data/scripts/collect-exports +76 -0
  40. pyflyby-1.9.4.data/scripts/collect-imports +58 -0
  41. pyflyby-1.9.4.data/scripts/find-import +38 -0
  42. pyflyby-1.9.4.data/scripts/list-bad-xrefs +34 -0
  43. pyflyby-1.9.4.data/scripts/prune-broken-imports +34 -0
  44. pyflyby-1.9.4.data/scripts/pyflyby-diff +34 -0
  45. pyflyby-1.9.4.data/scripts/reformat-imports +27 -0
  46. pyflyby-1.9.4.data/scripts/replace-star-imports +37 -0
  47. pyflyby-1.9.4.data/scripts/tidy-imports +191 -0
  48. pyflyby-1.9.4.data/scripts/transform-imports +47 -0
  49. pyflyby-1.9.4.dist-info/LICENSE.txt +23 -0
  50. pyflyby-1.9.4.dist-info/METADATA +507 -0
  51. pyflyby-1.9.4.dist-info/RECORD +54 -0
  52. pyflyby-1.9.4.dist-info/WHEEL +5 -0
  53. pyflyby-1.9.4.dist-info/entry_points.txt +3 -0
  54. pyflyby-1.9.4.dist-info/top_level.txt +1 -0
pyflyby/_modules.py ADDED
@@ -0,0 +1,515 @@
1
+ # pyflyby/_modules.py.
2
+ # Copyright (C) 2011, 2012, 2013, 2014, 2015 Karl Chen.
3
+ # License: MIT http://opensource.org/licenses/MIT
4
+
5
+
6
+
7
+
8
+ import ast
9
+ from functools import total_ordering
10
+ import itertools
11
+ import os
12
+
13
+ from pyflyby._file import FileText, Filename
14
+ from pyflyby._idents import DottedIdentifier, is_identifier
15
+ from pyflyby._log import logger
16
+ from pyflyby._util import (ExcludeImplicitCwdFromPathCtx,
17
+ cached_attribute, cmp, memoize,
18
+ prefixes)
19
+
20
+ import re
21
+ from six import reraise
22
+ import sys
23
+ import types
24
+ from typing import Any, Dict
25
+
26
+ class ErrorDuringImportError(ImportError):
27
+ """
28
+ Exception raised by import_module if the module exists but an exception
29
+ occurred while attempting to import it. That nested exception could be
30
+ ImportError, e.g. if a module tries to import another module that doesn't
31
+ exist.
32
+ """
33
+
34
+
35
+ @memoize
36
+ def import_module(module_name):
37
+ module_name = str(module_name)
38
+ logger.debug("Importing %r", module_name)
39
+ try:
40
+ result = __import__(module_name, fromlist=['dummy'])
41
+ if result.__name__ != module_name:
42
+ logger.debug("Note: import_module(%r).__name__ == %r",
43
+ module_name, result.__name__)
44
+ return result
45
+ except ImportError as e:
46
+ # We got an ImportError. Figure out whether this is due to the module
47
+ # not existing, or whether the module exists but caused an ImportError
48
+ # (perhaps due to trying to import another problematic module).
49
+ # Do this by looking at the exception traceback. If the previous
50
+ # frame in the traceback is this function (because locals match), then
51
+ # it should be the internal import machinery reporting that the module
52
+ # doesn't exist. Re-raise the exception as-is.
53
+ # If some sys.meta_path or other import hook isn't compatible with
54
+ # such a check, here are some things we could do:
55
+ # - Use pkgutil.find_loader() after the fact to check if the module
56
+ # is supposed to exist. Note that we shouldn't rely solely on
57
+ # this before attempting to import, because find_loader() doesn't
58
+ # work with meta_path.
59
+ # - Write a memoized global function that compares in the current
60
+ # environment the difference between attempting to import a
61
+ # non-existent module vs a problematic module, and returns a
62
+ # function that uses the working discriminators.
63
+ real_importerror1 = type(e) is ImportError
64
+ real_importerror2 = (sys.exc_info()[2].tb_frame.f_locals is locals())
65
+ m = re.match("^No module named (.*)$", str(e))
66
+ real_importerror3 = (m and m.group(1) == module_name
67
+ or module_name.endswith("."+m.group(1)))
68
+ logger.debug("import_module(%r): real ImportError: %s %s %s",
69
+ module_name,
70
+ real_importerror1, real_importerror2, real_importerror3)
71
+ if real_importerror1 and real_importerror2 and real_importerror3:
72
+ raise
73
+ reraise(ErrorDuringImportError, ErrorDuringImportError(
74
+ "Error while attempting to import %s: %s: %s"
75
+ % (module_name, type(e).__name__, e)), sys.exc_info()[2])
76
+ except Exception as e:
77
+ reraise(ErrorDuringImportError, ErrorDuringImportError(
78
+ "Error while attempting to import %s: %s: %s"
79
+ % (module_name, type(e).__name__, e)), sys.exc_info()[2])
80
+
81
+
82
+ def _my_iter_modules(path, prefix=''):
83
+ # Modified version of pkgutil.ImpImporter.iter_modules(), patched to
84
+ # handle inaccessible subdirectories.
85
+ if path is None:
86
+ return
87
+ try:
88
+ filenames = os.listdir(path)
89
+ except OSError:
90
+ return # silently ignore inaccessible paths
91
+ filenames.sort() # handle packages before same-named modules
92
+ yielded = {}
93
+ import inspect
94
+ for fn in filenames:
95
+ modname = inspect.getmodulename(fn)
96
+ if modname=='__init__' or modname in yielded:
97
+ continue
98
+ subpath = os.path.join(path, fn)
99
+ ispkg = False
100
+ try:
101
+ if not modname and os.path.isdir(path) and '.' not in fn:
102
+ modname = fn
103
+ for fn in os.listdir(subpath):
104
+ subname = inspect.getmodulename(fn)
105
+ if subname=='__init__':
106
+ ispkg = True
107
+ break
108
+ else:
109
+ continue # not a package
110
+ except OSError:
111
+ continue # silently ignore inaccessible subdirectories
112
+ if modname and '.' not in modname:
113
+ yielded[modname] = 1
114
+ yield prefix + modname, ispkg
115
+
116
+
117
+ def pyc_to_py(filename):
118
+ if filename.endswith(".pyc") or filename.endswith(".pyo"):
119
+ filename = filename[:-1]
120
+ return filename
121
+
122
+
123
+ @total_ordering
124
+ class ModuleHandle(object):
125
+ """
126
+ A handle to a module.
127
+ """
128
+
129
+ name: DottedIdentifier
130
+
131
+ def __new__(cls, arg):
132
+ if isinstance(arg, cls):
133
+ return arg
134
+ if isinstance(arg, Filename):
135
+ return cls._from_filename(arg)
136
+ if isinstance(arg, (str, DottedIdentifier)):
137
+ return cls._from_modulename(arg)
138
+ if isinstance(arg, types.ModuleType):
139
+ return cls._from_module(arg)
140
+ raise TypeError("ModuleHandle: unexpected %s" % (type(arg).__name__,))
141
+
142
+ _cls_cache:Dict[Any, Any] = {}
143
+
144
+ @classmethod
145
+ def _from_modulename(cls, modulename):
146
+ modulename = DottedIdentifier(modulename)
147
+ try:
148
+ return cls._cls_cache[modulename]
149
+ except KeyError:
150
+ pass
151
+ self = object.__new__(cls)
152
+ self.name = modulename
153
+ cls._cls_cache[modulename] = self
154
+ return self
155
+
156
+ @classmethod
157
+ def _from_module(cls, module):
158
+ if not isinstance(module, types.ModuleType):
159
+ raise TypeError
160
+ self = cls._from_modulename(module.__name__)
161
+ assert self.module is module
162
+ return self
163
+
164
+ @classmethod
165
+ def _from_filename(cls, filename):
166
+ filename = Filename(filename)
167
+ raise NotImplementedError(
168
+ "TODO: look at sys.path to guess module name")
169
+
170
+ @cached_attribute
171
+ def parent(self):
172
+ if not self.name.parent:
173
+ return None
174
+ return ModuleHandle(self.name.parent)
175
+
176
+ @cached_attribute
177
+ def ancestors(self):
178
+ return tuple(ModuleHandle(m) for m in self.name.prefixes)
179
+
180
+ @cached_attribute
181
+ def module(self):
182
+ """
183
+ Return the module instance.
184
+
185
+ :rtype:
186
+ ``types.ModuleType``
187
+ :raise ErrorDuringImportError:
188
+ The module should exist but an error occurred while attempting to
189
+ import it.
190
+ :raise ImportError:
191
+ The module doesn't exist.
192
+ """
193
+ # First check if prefix component is importable.
194
+ if self.parent:
195
+ self.parent.module
196
+ # Import.
197
+ return import_module(self.name)
198
+
199
+ @cached_attribute
200
+ def exists(self):
201
+ """
202
+ Return whether the module exists, according to pkgutil.
203
+ Note that this doesn't work for things that are only known by using
204
+ sys.meta_path.
205
+ """
206
+ name = str(self.name)
207
+ if name in sys.modules:
208
+ return True
209
+ if self.parent and not self.parent.exists:
210
+ return False
211
+
212
+ import importlib.util
213
+ find = importlib.util.find_spec
214
+
215
+ try:
216
+ pkg = find(name)
217
+ except Exception:
218
+ # Catch all exceptions, not just ImportError. If the __init__.py
219
+ # for the parent package of the module raises an exception, it'll
220
+ # propagate to here.
221
+ pkg = None
222
+ return pkg is not None
223
+
224
+ @cached_attribute
225
+ def filename(self):
226
+ """
227
+ Return the filename, if appropriate.
228
+
229
+ The module itself will not be imported, but if the module is not a
230
+ top-level module/package, accessing this attribute may cause the
231
+ parent package to be imported.
232
+
233
+ :rtype:
234
+ `Filename`
235
+ """
236
+ if sys.version_info > (3, 12):
237
+ from importlib.util import find_spec
238
+ try:
239
+ mod = find_spec(str(self.name))
240
+ if mod is None or mod.origin is None:
241
+ return None
242
+ else:
243
+ assert isinstance(mod.origin, str)
244
+ return Filename(mod.origin)
245
+ except ModuleNotFoundError:
246
+ return None
247
+ assert False
248
+
249
+ # Use the loader mechanism to find the filename. We do so instead of
250
+ # using self.module.__file__, because the latter forces importing a
251
+ # module, which may be undesirable.
252
+
253
+ import pkgutil
254
+ try:
255
+ #TODO: deprecated and will be removed in 3.14
256
+ loader = pkgutil.get_loader(str(self.name))
257
+ except ImportError:
258
+ return None
259
+ if not loader:
260
+ return None
261
+ # Get the filename using loader.get_filename(). Note that this does
262
+ # more than just loader.filename: for example, it adds /__init__.py
263
+ # for packages.
264
+ if not hasattr(loader, 'get_filename'):
265
+ return None
266
+ filename = loader.get_filename()
267
+ if not filename:
268
+ return None
269
+ return Filename(pyc_to_py(filename))
270
+
271
+ @cached_attribute
272
+ def text(self):
273
+ return FileText(self.filename)
274
+
275
+ def __text__(self):
276
+ return self.text
277
+
278
+ @cached_attribute
279
+ def block(self):
280
+ from pyflyby._parse import PythonBlock
281
+ return PythonBlock(self.text)
282
+
283
+ @staticmethod
284
+ @memoize
285
+ def list():
286
+ """
287
+ Enumerate all top-level packages/modules.
288
+
289
+ :rtype:
290
+ ``tuple`` of `ModuleHandle` s
291
+ """
292
+ import pkgutil
293
+ # Get the list of top-level packages/modules using pkgutil.
294
+ # We exclude "." from sys.path while doing so. Python includes "." in
295
+ # sys.path by default, but this is undesirable for autoimporting. If
296
+ # we autoimported random python scripts in the current directory, we
297
+ # could accidentally execute code with side effects. If the current
298
+ # working directory is /tmp, trying to enumerate modules there also
299
+ # causes problems, because there are typically directories there not
300
+ # readable by the current user.
301
+ with ExcludeImplicitCwdFromPathCtx():
302
+ modlist = pkgutil.iter_modules(None)
303
+ module_names = [t[1] for t in modlist]
304
+ # pkgutil includes all *.py even if the name isn't a legal python
305
+ # module name, e.g. if a directory in $PYTHONPATH has files named
306
+ # "try.py" or "123.py", pkgutil will return entries named "try" or
307
+ # "123". Filter those out.
308
+ module_names = [m for m in module_names if is_identifier(m)]
309
+ # Canonicalize.
310
+ return tuple(ModuleHandle(m) for m in sorted(set(module_names)))
311
+
312
+ @cached_attribute
313
+ def submodules(self):
314
+ """
315
+ Enumerate the importable submodules of this module.
316
+
317
+ >>> ModuleHandle("email").submodules # doctest:+ELLIPSIS
318
+ (..., ModuleHandle('email.encoders'), ..., ModuleHandle('email.mime'), ...)
319
+
320
+ :rtype:
321
+ ``tuple`` of `ModuleHandle` s
322
+ """
323
+ import pkgutil
324
+ module = self.module
325
+ try:
326
+ path = module.__path__
327
+ except AttributeError:
328
+ return ()
329
+ # Enumerate the modules at a given path. Prefer to use ``pkgutil`` if
330
+ # we can. However, if it fails due to OSError, use our own version
331
+ # which is robust to that.
332
+ try:
333
+ submodule_names = [t[1] for t in pkgutil.iter_modules(path)]
334
+ except OSError:
335
+ submodule_names = [t[0] for p in path for t in _my_iter_modules(p)]
336
+ return tuple(ModuleHandle("%s.%s" % (self.name,m))
337
+ for m in sorted(set(submodule_names)))
338
+
339
+ @staticmethod
340
+ def _member_from_node(node):
341
+ extractors = {
342
+ # Top-level assignments (as opposed to member assignments
343
+ # whose targets are of type ast.Attribute).
344
+ ast.Assign: lambda x: [t.id for t in x.targets if isinstance(t, ast.Name)],
345
+ ast.ClassDef: lambda x: [x.name],
346
+ ast.FunctionDef: lambda x: [x.name],
347
+ }
348
+ if isinstance(node, tuple(extractors.keys())):
349
+ return extractors[type(node)](node)
350
+ return []
351
+
352
+ @cached_attribute
353
+ def exports(self):
354
+ """
355
+ Get symbols exported by this module.
356
+
357
+ Note that this will not recognize symbols that are dynamically
358
+ introduced to the module's namespace or __all__ list.
359
+
360
+ :rtype:
361
+ `ImportSet` or ``None``
362
+ :return:
363
+ Exports, or ``None`` if nothing exported.
364
+ """
365
+ from pyflyby._importclns import ImportStatement, ImportSet
366
+
367
+ filename = getattr(self, 'filename', None)
368
+ if not filename or not filename.exists:
369
+ # Try to load the module to get the filename
370
+ filename = Filename(self.module.__file__)
371
+ text = FileText(filename)
372
+
373
+ ast_mod = ast.parse(str(text), str(filename)).body
374
+
375
+ # First, add members that are explicitly defined in the module
376
+ members = list(itertools.chain(*[self._member_from_node(n) \
377
+ for n in ast_mod]))
378
+
379
+ # If __all__ is defined, try to use it
380
+ all_is_good = False # pun intended
381
+ all_members = []
382
+ if "__all__" in members:
383
+ # Iterate through the nodes and reconstruct the
384
+ # value of __all__
385
+ for n in ast_mod:
386
+ if isinstance(n, ast.Assign):
387
+ if "__all__" in self._member_from_node(n):
388
+ try:
389
+ all_members = list(ast.literal_eval(n.value))
390
+ all_is_good = True
391
+ except (ValueError, TypeError):
392
+ all_is_good = False
393
+ elif isinstance(n, ast.AugAssign) and \
394
+ isinstance(n.target, ast.Name) and \
395
+ n.target.id == "__all__" and all_is_good:
396
+ try:
397
+ all_members += list(ast.literal_eval(n.value))
398
+ except (ValueError, TypeError):
399
+ all_is_good = False
400
+ if not all(type(s) == str for s in members):
401
+ raise Exception(
402
+ "Module %r contains non-string entries in __all__"
403
+ % (str(self.name),))
404
+
405
+ if all_is_good:
406
+ members = all_members
407
+ else:
408
+ # Add "from" imports that belong to submodules
409
+ # (note: this will fail to recognize implicit relative imports)
410
+ imp_nodes = [n for n in ast_mod if isinstance(n, ast.ImportFrom)]
411
+ for imp_node in imp_nodes:
412
+ if imp_node.level == 0:
413
+ from_mod = DottedIdentifier(imp_node.module)
414
+ if not from_mod.startswith(self.name):
415
+ continue
416
+ elif imp_node.level == 1 and \
417
+ filename.base == "__init__.py":
418
+ # Special case: a relative import can be from a submodule only if
419
+ # our module's filename is __init__.py.
420
+ from_mod = self.name
421
+ if imp_node.module:
422
+ from_mod += imp_node.module
423
+ else:
424
+ continue
425
+ for n in imp_node.names:
426
+ m = n.asname or n.name
427
+ if n.name != "*" and not ModuleHandle(from_mod + m).exists:
428
+ members.append(m)
429
+
430
+ # Filter by non-private.
431
+ members = [n for n in members if not n.startswith("_")]
432
+
433
+ # Filter out artificially added "deep" members.
434
+ members = tuple([(n, None) for n in members if "." not in n])
435
+ if not members:
436
+ return None
437
+ return ImportSet(
438
+ [ ImportStatement.from_parts(str(self.name), members) ])
439
+
440
+ def __str__(self):
441
+ return str(self.name)
442
+
443
+ def __repr__(self):
444
+ return "%s(%r)" % (type(self).__name__, str(self.name))
445
+
446
+ def __hash__(self):
447
+ return hash(self.name)
448
+
449
+ def __cmp__(self, o):
450
+ if self is o:
451
+ return 0
452
+ if not isinstance(o, ModuleHandle):
453
+ return NotImplemented
454
+ return cmp(self.name, o.name)
455
+
456
+ def __eq__(self, o):
457
+ if self is o:
458
+ return True
459
+ if not isinstance(o, ModuleHandle):
460
+ return NotImplemented
461
+ return self.name == o.name
462
+
463
+ def __ne__(self, other):
464
+ return not (self == other)
465
+
466
+ # The rest are defined by total_ordering
467
+ def __lt__(self, o):
468
+ if not isinstance(o, ModuleHandle):
469
+ return NotImplemented
470
+ return self.name < o.name
471
+
472
+ def __getitem__(self, x):
473
+ if isinstance(x, slice):
474
+ return type(self)(self.name[x])
475
+ raise TypeError
476
+
477
+ @classmethod
478
+ def containing(cls, identifier):
479
+ """
480
+ Try to find the module that defines a name such as ``a.b.c`` by trying
481
+ to import ``a``, ``a.b``, and ``a.b.c``.
482
+
483
+ :return:
484
+ The name of the 'deepest' module (most commonly it would be ``a.b``
485
+ in this example).
486
+ :rtype:
487
+ `Module`
488
+ """
489
+ # In the code below we catch "Exception" rather than just ImportError
490
+ # or AttributeError since importing and __getattr__ing can raise other
491
+ # exceptions.
492
+ identifier = DottedIdentifier(identifier)
493
+ try:
494
+ module = ModuleHandle(identifier[:1])
495
+ result = module.module
496
+ except Exception as e:
497
+ raise ImportError(e)
498
+ # TODO: as far as I can tell the code here is never reached, or haven't
499
+ # been in quite some time as the line below was invalid on Python 3 since 2011
500
+ # zip(...)[...] fails as zip is not indexable.
501
+ # the only place that seem to be using this method is XrefScanner.
502
+ for part, prefix in list(zip(identifier, prefixes(identifier)))[1:]:
503
+ try:
504
+ result = getattr(result, str(part))
505
+ except Exception:
506
+ try:
507
+ module = cls(prefix)
508
+ result = module.module
509
+ except Exception as e:
510
+ raise ImportError(e)
511
+ else:
512
+ if isinstance(result, types.ModuleType):
513
+ module = cls(result)
514
+ logger.debug("Imported %r to get %r", module, identifier)
515
+ return module